質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
WebSocket

WebSocketとは双方向・全二重コミュニケーションのためのAPIでありプロトコルのことを指します。WebSocketはHTML5に密接に結びついており、多くのウェブブラウザの最新版に導入されています。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

解決済

2回答

349閲覧

ESP32で特定の処理を行うとWebsocket通信が出来なくなるのを解決したい

kurozaemon

総合スコア2

WebSocket

WebSocketとは双方向・全二重コミュニケーションのためのAPIでありプロトコルのことを指します。WebSocketはHTML5に密接に結びついており、多くのウェブブラウザの最新版に導入されています。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

1クリップ

投稿2024/01/26 20:57

実現したいこと

ESP32とスマホをソフトAP接続してお互いにブラウザを通じて操作・情報表示をしたい。

スマホからは番号入力・スタートボタン・リセットボタンを配置し、受け取った数値・文字列を表示する部分があります。
ESP32はソフトAPとして動作しスマホの接続を受入れ、他のマイコンとハードウエアシリアル接続しており受信した文字列を読み込み一時保存。スマホからの数値・セット/リセット入力を受け付け、外部入力スイッチによるカウント処理を行う。
セットでフラグを立てて、外部入力でカウントされた数値とスマホからの数値入力が一致したらフラグをなくす。リセットはそのフラグとスマホからの数値入力を0にする。

Websocketで送られるstringの文字列は数字2桁+数字2桁+文字列3文字が基本で、シリアルで受け取った文字列は日本語で最大10文字です。

こんな感じです。

発生している問題・分からないこと

シリアル通信で文字列を受け取るとスマホとの通信が不安定になり、本来ならばwebsocketで数値・文字列は自動更新されるはずが出来なくなってしまいます。
(その場合手動でブラウザを更新すれば反映はされます)

シリアルモニターで見てもWebsocketが出来なくなった状態でもWebSocket client connectedのままでdisconnectedは表示されず

エラーメッセージ

error

1エラーメッセージは表示されず

該当のソースコード

arduino

1#include <WiFi.h> 2#include <ESPAsyncWebServer.h> 3#include <AsyncWebSocket.h> 4 5const char ssid[] = "ESP32-AP"; // ソフトAPのSSID 6const char password[] = "123456789"; // ソフトAPのパスワード 7 8const int upswitchPin = 17; // スイッチのピン番号 9const int dnswitchPin = 16; // スイッチのピン番号 10 11AsyncWebServer server(80); 12AsyncWebSocket ws("/ws"); 13 14int now = 0; 15bool set = false; 16int data = 0; 17String NAIYOU; 18 19bool upswitchState = false; 20bool dnswitchState = false; 21bool lastupSwitchState = false; 22bool lastdnSwitchState = false; 23 24HardwareSerial myHardwareSerial(1); //シリアル1をmyHardwareSerialと定義 25 26void notifyClients() { 27 String response = "{\"now\":" + String(now) + ", \"set\":" + String(set ? "true" : "false") + ", \"data\":" + String(data) + ", \"NAIYOU\":\"" + NAIYOU + "\"}"; 28 ws.textAll(response); 29} 30 31void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) { 32 AwsFrameInfo *info = (AwsFrameInfo *)arg; 33 if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) { 34 data[len] = 0; 35 String message = (char *)data; 36 if (message.startsWith("SET,")) { 37 message.remove(0, 4); // "SET,"を取り除く 38 int newNow = message.toInt(); 39 if (!isnan(newNow) && newNow >= 1 && newNow <= 70) { 40 now = newNow; 41 set = true; 42 notifyClients(); 43 } else { 44 Serial.println("Invalid number for now"); 45 } 46 } else if (message == "RESET") { 47 now = 0; 48 set = false; 49 notifyClients(); 50 } 51 } 52} 53 54void setup() { 55 Serial.begin(115200); 56 myHardwareSerial.begin(115200, SERIAL_8N1, 27, 26); 57 58 pinMode(upswitchPin, INPUT_PULLUP); 59 pinMode(dnswitchPin, INPUT_PULLUP); 60 61 // ソフトAPモードでWiFiを開始 62 WiFi.softAP(ssid, password); 63 IPAddress IP = WiFi.softAPIP(); 64 Serial.println("AP IP address: " + IP.toString()); 65 66 // WebSocketの設定 67 ws.onEvent([](AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { 68 if (type == WS_EVT_CONNECT) { 69 Serial.println("WebSocket client connected"); 70 } else if (type == WS_EVT_DISCONNECT) { 71 Serial.println("WebSocket client disconnected"); 72 } else if (type == WS_EVT_DATA) { 73 handleWebSocketMessage(arg, data, len); 74 } 75 }); 76 77 server.addHandler(&ws); 78 79 server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { 80 String html = "<html><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'>" 81 "<style>" 82 "body { font-size: 20px; text-align: center; color: black; font-family: 'MS Gothic', sans-serif; }" 83 "table { margin: 0 auto; font-size: 20px; border: 1px solid black; table-layout: fixed; width: 50%; background-color: white; color: black; }" 84 "th, td { padding: 10px; text-align: center; word-wrap: break-word; }" 85 "button { font-size: 24px; border-radius: 12px; padding: 10px 20px; margin: 5px; }" 86 "input { font-size: 24px; padding: 10px; width: 50px; text-align: center; }" 87 "</style></head><body>"; 88 html += "<table border='1'>"; 89 html += "<tr><th>設定</th><th>現在</th><th>状態</th></tr>"; 90 html += "<tr><td id='now'>" + String(now) + "</td><td id='data'>" + String(data) + "</td><td id='set'>" + String(set && now != data ? "指令中" : "") + "</td></tr>"; 91 html += "</table><br>"; 92 html += "<label for='inputNow'>設定番号:</label><input type='number' id='inputNow' name='inputNow' min='1' max='70'><br>"; 93 html += "<button id='setButton' onclick='sendRequest(\"SET\")'>SET</button>"; 94 html += "<button onclick='sendRequest(\"RESET\")'>RESET</button>"; 95 html += "<p>NAIYOU: " + NAIYOU + "</p>"; 96 html += "<script>" 97 "var socket = new WebSocket('ws://' + window.location.hostname + ':80/ws');" 98 "socket.onmessage = function(event) {" 99 " var data = JSON.parse(event.data);" 100 " document.getElementById('now').innerHTML = data.now;" 101 " if (data.now === data.data) {" 102 " document.getElementById('set').innerHTML = '';" 103 " data.set = false;" 104 " document.getElementById('setButton').style.backgroundColor = '';" 105 " } else {" 106 " document.getElementById('set').innerHTML = data.set ? '設定中' : '';" 107 " document.getElementById('setButton').style.backgroundColor = data.set ? 'red' : '';" 108 " }" 109 " document.getElementById('data').innerHTML = data.data;" 110 " document.getElementById('NAIYOU').innerHTML = 'NAIYOU: ' + data.NAIYOU;" 111 "};" 112 "function sendRequest(action) {" 113 " if (action === 'SET') {" 114 " var inputValue = document.getElementById('inputNow').value;" 115 " if (inputValue !== '' && !isNaN(inputValue) && inputValue >= 1 && inputValue <= 70) {" 116 " socket.send(action + ',' + inputValue);" 117 " document.getElementById('inputNow').value = '';" 118 " } else {" 119 " alert('設定番号を正しく入力してください (1~70)');" 120 " }" 121 " } else {" 122 " socket.send(action);" 123 " }" 124 "}" 125 "</script>"; 126 html += "</body></html>"; 127 request->send(200, "text/html", html); 128 }); 129 130 server.begin(); 131} 132 133void loop() { 134 upswitchState = digitalRead(upswitchPin); 135 if (upswitchState != lastupSwitchState && upswitchState == LOW) { 136 data++; 137 if (data > 69) data = 70; 138 myHardwareSerial.print(data); 139 } 140 lastupSwitchState = upswitchState; 141 142 dnswitchState = digitalRead(dnswitchPin); 143 if (dnswitchState != lastdnSwitchState && dnswitchState == LOW) { 144 data--; 145 if (data < 1) data = 1; 146 myHardwareSerial.print(data); 147 } 148 lastdnSwitchState = dnswitchState; 149 150 // nowとdataが一致したらsetを0にする 151 if (now == data) { 152 set = false; 153 } 154 // シリアルからの受信処理 155 if (myHardwareSerial.available() > 0) { 156 NAIYOU = myHardwareSerial.readStringUntil('\n'); 157 Serial.println(NAIYOU); 158 } 159 notifyClients(); 160 delay(50); // 10ミリ秒のディレイ 161}

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

該当する検索ヒットは見つけられず

補足

特になし

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

待ちとかそういうの全然関係なくて、'NAIYOU'を受け取るものが無いという話と、文字列に改行を含めるなという話、みたいです。

Arduino

1void setup() 2{ 3 //略 4 // NAIYOUを受け取るモノを作ってやる 5 html += "<p>NAIYOU: <span id='NAIYOU'>"+ NAIYOU +"</span> </p>"; 6 //略 7 // 表示のNAIYOU:が重なるので削除 8 " document.getElementById('NAIYOU').innerHTML = data.NAIYOU;" 9 //略 10} 11 12void loop() 13{ 14 //略 15 // シリアルからの受信処理 16 if (myHardwareSerial.available() > 0) 17 { 18 NAIYOU = myHardwareSerial.readStringUntil('\n'); 19 NAIYOU.trim(); //改行コード削除 20 } 21 //略 22}

投稿2024/01/27 13:22

thkana

総合スコア7639

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kurozaemon

2024/01/27 16:17

回答ありがとうございます。試してみましたが解決できませんでした。 しかしながら変化は無くシリアル通信で相手からのデータを貰うと以後、Websocketが停止するのかスマホへのデータが送られなくなてしまいます。(手動でリロードすれば変化しますが…)
thkana

2024/01/28 10:12

そうですか。私の手元では動いたので、なにが違うのでしょうね。不思議ですね。 > しかしながら変化は無く しかしながら、というのは日本語としては「なにか別のことが起こった」というときのつなぎの言葉なので「解決には至らずともなにかが変わった」という文章になるのかと思いましたが、「変化は無く」なのですか?
kurozaemon

2024/01/29 09:12

色々試したところ問題が解決しました!原因は送られてくるデータの末尾に余計な"が入ってた様で、これを送られないように修正したら問題なく動く様になりました。 スケッチの重複部分など指摘いただいたのでベストアンサーに選ばせていただきました。
thkana

2024/01/29 12:44

差し支えなければ、動作したプログラム全文を質問に追記しておいていただけると参考になるかと思います。
guest

0

if (myHardwareSerial.available() > 0) {
NAIYOU = myHardwareSerial.readStringUntil('\n');
Serial.println(NAIYOU);
}

律儀にここで受信待ちをしてますが、ここで待っている間、ネットワーク操作ができなくなります
また、わざわざループの中でdelayを使ってますがこれもまたこの不具合に拍車をかけています
無駄な待ちをしないようにする必要があります

投稿2024/01/26 23:45

y_waiwai

総合スコア87776

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

thkana

2024/01/27 00:51

> わざわざループの中でdelayを使って いやいや、RTOSを使っている(ESP32のボードライブラリは中でFreeRTOSが動いている)場合には、delayというのは単に「何もしない」のではなくて、実行権を(少なくともdelay時間の間)OSに返してタスクは休眠するということだから、急ぎの仕事がないときにdelayして他のタスクに制御を渡すのは「無駄な待ち」とは違う。とはいえ、多分loop()を抜けてたところで他のタスクを実行するだろうからその場所でのdelayにはあまり意味はないかも知れないけれど。 タスクの独占という意味では、HardwareSerial::readStringUntil()のループ中にタスクスイッチの機会はなさそうだから、readStringUntilじゃなくて自分で一文字ずつ取得して、行末を待たないようにすればなにか変わるかも?
y_waiwai

2024/01/27 01:57

まあ、arduinoってついてますし、そこらへんはどーなのかなと。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問