リレーとサーボモーターの動作確認が出来たところで、実際のポイント制御に応用するべく、これらを何セットか動かす環境へと持って行く。今回は手持ちパーツの都合上、2セットを動かす回路及びプログラムを組んでみた。
[ スケッチ:Esp32_AsyncWebServer_Relay ]
#include <WiFi.h>
#include "ESPAsyncWebServer.h"
#include "SPIFFS.h"
#include <ArduinoJson.h>
#include <ESP32Servo.h> // for Servo
#include <ServoEasing.hpp>
const char ssid[] = "********";
const char pass[] = "********";
const IPAddress ip(192,168,3,17);
const IPAddress gateway(192,168,1,1); // デフォルトゲートウェイ
const IPAddress subnet(255,255,255,0);
const int rel_pins[] = {0,32,33}; // リレー用Pin
const int srv_pins[] = {1,18,19}; // サーボ用Pin
const int SIZEOF_REL_PINS = sizeof(rel_pins)/sizeof(rel_pins[0]);
const int srv_min = 1000;
const int srv_max = 2000;
const int srv_hrz = 50;
const int srv_deg = 180;
const int srv_sec = 2000;
AsyncWebServer server(80); // ポート設定
// Jsonオブジェクトの初期化
StaticJsonDocument<512> doc;
// ブラウザから受信する変数
uint8_t pnt_number; // ポイント配置番号
uint8_t pnt_status; // ポイント状態制御
// for Servo
ServoEasing servo1; // create servo object to control a servo
ServoEasing servo2; // create servo object to control a servo
void setup()
{
Serial.begin(115200);
for(int i =1; i <= SIZEOF_REL_PINS; i++) {
pinMode(rel_pins[i], OUTPUT); // pinを出力設定に
pinMode(srv_pins[i], OUTPUT); // pinを出力設定に
}
// SPIFFSのセットアップ
if(!SPIFFS.begin(true)){
Serial.println("An Error has occurred while mounting SPIFFS");
return;
}
WiFi.config(ip, gateway, subnet);
WiFi.begin (ssid, pass);
while ( WiFi.status() != WL_CONNECTED ) {
delay ( 1000 );
Serial.print ( "." );
}
// 各種情報を表示
Serial.print("SSID: ");
Serial.println(ssid);
Serial.print("AP IP address: ");
Serial.println(ip);
// GETリクエストに対するハンドラーを登録
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/index.html"); // rootにアクセスされた時のレスポンス
});
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/style.css", "text/css"); // style.cssにアクセスされた時のレスポンス
});
// Pointの制御変数の変更リクエスト
server.on(
"/post_test",
HTTP_POST,
[](AsyncWebServerRequest * request){},
NULL,
[](AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total) {
String resjson = "";
for (size_t i = 0; i < len; i++) {
//Serial.write(data[i]);
resjson.concat(char(data[i]));
}
Serial.println(resjson);
DeserializationError error = deserializeJson(doc, resjson);
if(error){
Serial.println("deserializeJson() faild");
request->send(400);
}
else{
pnt_number = doc["PNT_NUMBER"];
pnt_status = doc["PNT_STATUS"];
request->send(200);
}
});
pnt_number = 0;
pnt_status = 0;
// サーバースタート
server.begin();
Serial.println("Server start!");
// for Servo
servo1.setEasingType(EASE_CUBIC_IN_OUT); // EASE_LINEAR is default
servo1.setPeriodHertz(srv_hrz); // setPeriodHertz(int hertz)
servo1.attach(srv_pins[1], srv_min, srv_max); // attach(int pin, int min, int max)
servo2.setEasingType(EASE_CUBIC_IN_OUT); // EASE_LINEAR is default
servo2.setPeriodHertz(srv_hrz); // setPeriodHertz(int hertz)
servo2.attach(srv_pins[2], srv_min, srv_max); // attach(int pin, int min, int max)
} // End setup()
void loop() {
if(pnt_number > 0) {
// Relay
relayGo(pnt_number, pnt_status);
// Servo
servoGo(pnt_number, pnt_status);
}
pnt_number = 0;
delay(10);
} // End loop()
void relayGo(int pnt_number, int pnt_status) {
if(pnt_status == 0){
digitalWrite(rel_pins[pnt_number], LOW);
} else {
digitalWrite(rel_pins[pnt_number], HIGH);
}
}
void servoGo(int pnt_number, int pnt_status) {
if(pnt_number == 1) {
servo1.setEaseToD(pnt_status*srv_deg, srv_sec); // setEaseToD(int aTargetDegreeOrMicrosecond, uint_fast16_t aMillisForMove)
}
if(pnt_number == 2) {
servo2.setEaseToD(pnt_status*srv_deg, srv_sec); // setEaseToD(int aTargetDegreeOrMicrosecond, uint_fast16_t aMillisForMove)
}
synchronizeAllServosStartAndWaitForAllServosToStop();
}
[ HTML:index.html ]
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" charset="UTF-8">
<title>ESP32 Web Server</title>
<link rel="icon" href="data:,">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>ESP32 Web Server</h1>
<div id="btn_msg" style="visibility:hidden;">送信OK</div>
<div style="margin: 0 2em; padding: 1em; border: solid 1px #aac; width: 10em;">
1:<input type="radio" onclick="send_status(parseInt(this.name), 1);" name="1">R<br>
1:<input type="radio" onclick="send_status(parseInt(this.name), 0);" name="1">L<br>
2:<input type="radio" onclick="send_status(parseInt(this.name), 1);" name="2">R<br>
2:<input type="radio" onclick="send_status(parseInt(this.name), 0);" name="2">L</div>
</body>
<script>
// json返り値のテンプレート
var json_temp = {
PNT_NUMBER: 1,
PNT_STATUS: 0
}
// 送信ステータス表示
function btn_msg_display(msg_txt, txt_color){
var id_btn_msg = document.getElementById("btn_msg")
id_btn_msg.style.color = txt_color;
id_btn_msg.textContent = msg_txt;
id_btn_msg.style.visibility ="visible";
}
// タイムスタンプ文字列の作成
function get_time_stamp() {
var now_time = new Date();
var now_date = ('000' + now_time.getFullYear()).slice(-4) + '-' + ('0' + (now_time.getMonth() + 1)).slice(-2) + '-' + ('0' + now_time.getDate()).slice(-2);
var now_time_val = ('0' + now_time.getHours()).slice(-2) + ':' + ('0' + now_time.getMinutes()).slice(-2) + ':' + ('0' + now_time.getSeconds()).slice(-2);
var time_stamp = now_date + " " + now_time_val + " ";
return time_stamp;
}
// Pointの状態変更リクエストの送信
function send_status(pnt, send_status){
var str_status = "";
if(send_status == 0){
str_status = "PNT_LEFT";
}
else{
str_status = "PNT_RIGHT";
}
// JSONデータの作成
var send_json = json_temp;
send_json.PNT_NUMBER = pnt;
send_json.PNT_STATUS = send_status;
send_json = JSON.stringify(send_json);
console.log(send_json);
// リクエストを送信
var xhr = new XMLHttpRequest()
xhr.open("POST", "/post_test", true)
xhr.setRequestHeader("Content-Type", "application/json")
xhr.timeout = 5000; // タイムアウト設定(ms)
xhr.onload = () => {
btn_msg_display(get_time_stamp() + str_status + " 送信 OK", "#00aa00");
};
xhr.onerror = () => {
btn_msg_display(get_time_stamp() + str_status + " 送信 NG", "#ff0000");
};
xhr.ontimeout = () => {
btn_msg_display(get_time_stamp() + str_status + " 送信 タイムアウト", "#ff0000");
};
xhr.send(send_json)
}
</script>
</html>
Web画面の方も、マルチ化と共に実使用状態に合わせて少し編集を入れた。今回のサンプルでは、Point1とPoint2を操作するパネルを想定し、それぞれRight/Leftを切り替えるラジオボタンを配している。クリックすると、JSON形式でPoint番号(PNT_NUMBER)と切替方向(PNT_STATUS)が送信されるようにした。とりあえずの動作確認用なので、今のところ見てくれは度外視している。
[ 画面表示:index.html ]
