me-no-dev / ESPAsyncWebServer

Async Web Server for ESP8266 and ESP32
3.8k stars 1.23k forks source link

WebSocketServer and analogRead(A0) conflict #944

Closed Akta3d closed 3 years ago

Akta3d commented 3 years ago

On a project I want to control LED and a MP3 player with a Wemos D1 mini, buttons, potentiometer and a html page. All work fine, without the volume potentiometer.

The wemos is the websocket server, and the HTML page the client. I can control LED and MP3 with button and/or html page.

But when I put analogRead(A0) in the source code, my websocket client fails to connect to the web socket server.

For this issue I have remove all uneeded code to just have the websocket server and the potentiometer.

Ardiuno Code:

#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>

#define SERVER_PORT 80
#define WEBSOCKET_PATH    "/ws"  

#define WIFI_SSID         "{ NEED CHANGE WITH YOUR WIFI SSID NAME }"
#define WIFI_PASSWORD     "{ NEED CHANGE WITH YOUR WIFI PASSWORD }"

#define PIN_VOLUME A0

uint16_t volume = 10;
AsyncWebServer server(SERVER_PORT);
AsyncWebSocket ws(WEBSOCKET_PATH);

void setup() {
  // Used for debugging messages
  Serial.begin(9600); 

  Serial.println("");
  Serial.println("");
  Serial.println("Setup Start");

  // Connect to Wi-Fi
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  // Print ESP Local IP Address
  Serial.println(WiFi.localIP());

  // Init WebSocket
  Serial.println("Init WebSocket");
  initWebSocket();

  // Start server
  Serial.println("Start server");
  server.begin();

  Serial.println("Setup OK");
}

void loop() {  
  ws.cleanupClients(); 

  int newAnalogValue = analogRead(PIN_VOLUME);
  //int newAnalogValue = 500;
  int newVolume = map(newAnalogValue, 0, 1024, 0, 30);
  if(newVolume != volume) {
    setVolume(newVolume);
  }
}

void setVolume(uint16_t newVolume) {
  if(newVolume < 0) newVolume = 0;
  if(newVolume > 30) newVolume = 30;

  volume = newVolume;
  Serial.print("volumePot = ");
  Serial.println(volume);

  notifyAllWsClients("volume:" + String(volume));
}

void notifyAllWsClients(String data) {
  // send data to all connected clients
  ws.textAll(data);
}

void notifyWsClient(uint32_t clientId, String data) {
  ws.text(clientId, data);
}

void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
  AwsFrameInfo *info = (AwsFrameInfo*)arg;
  if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
    data[len] = 0;

    String dataStr((char*)data);

    String action = dataStr;
    String value = "";
    int index = dataStr.indexOf(":");
    if(-1 != index) {
      action = dataStr.substring(0, index);
      value = dataStr.substring(index + 1);
    }

    Serial.print("Received event. Action: " + action);
    Serial.println(", Value: " + value);
  }
}

void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,
            void *arg, uint8_t *data, size_t len) {
    uint32_t clientId = -1;
    switch (type) {
      case WS_EVT_CONNECT:
        clientId = client->id();
        Serial.printf("WebSocket client #%u connected from %s\n", clientId, client->remoteIP().toString().c_str());

        break;
      case WS_EVT_DISCONNECT:
        Serial.printf("WebSocket client #%u disconnected\n", client->id());
        break;
      case WS_EVT_DATA:
        handleWebSocketMessage(arg, data, len);
        break;
      case WS_EVT_PONG:
      case WS_EVT_ERROR:
        break;
  }
}

void initWebSocket() {
  ws.onEvent(onEvent);
  server.addHandler(&ws);
}

The html page:

<!DOCTYPE HTML>
<html>
  <head>
    <title>Yuna MP3Lights</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>

  <body>
    <div class="topnav">
      <h1>Yuna MP3Lights</h1>
    </div>

    <div id="connectionGui">
      <h2>WebSocket Connection</h2>

      <label for="gatewayIpInput" class="label">Gateway IP for WebSocket connection</label>
      <input id="gatewayIpInput" class="input">
      <button id="changeGatewayIpButton" class="button">OK</button>
      <p id="connectionMessage"></p>
    </div>

    <div id="mainGui">
      <div class="card mp3">
        <div class="head">
          <h2>MP3</h2>
        </div>
        <div class="content center">     
          <div>          
            <input type="range" id="volumeSlider" min="0" max="30">
          </div>  
        </div>
      </div>

  <script src="./script.js"></script>
  </body>
</html>

The script:

var gatewayIp = '192.168.1.61';
var websocketRoot = '/ws';
var websocket;
var connected = false;
var forceDisplayGui = false; // allow to display main gui without connected socket

// global variables
var volume = 10;

// ------------ WEBSOCKET -------------------------
function initWebSocket() {
    if(connected) return;

    console.log('Trying to open a WebSocket connection...');

    var gateway = `ws://${gatewayIp}${websocketRoot}`;
    websocket = new WebSocket(gateway);
    websocket.onopen    = onOpen;
    websocket.onclose   = onClose;
    websocket.onmessage = onMessage;
}

function onOpen(event) {
    console.log('Connection opened');
    connected = true;
    switchGui();
}

function onClose(event) {
    console.log('Connection closed');
    connected = false;
    switchGui();
}

function onMessage(event) {
    var action = event.data;
    var value = 0;
    var pos = event.data.indexOf(':');
    if(pos !== -1) {
        action = event.data.substr(0, pos);
        value = event.data.substr(pos + 1);
    }
    console.log(`Received event. Action: ${action}, Value:${value}`);

    switch(action) {            
        case 'volume':
            volume = parseInt(value, 10);
            break;        
        default:
            console.error(`Unknown action: ${action}, Value:${value}`)
    }

    refreshMainGui();
}

// --------------- SETUP ------------------------
window.addEventListener('load', onLoad);
function onLoad(event) {
    var localIp = localStorage.getItem('gatewayIp');
    if(localIp) {
        gatewayIp = localIp;
    }

    // display connection or gui
    switchGui();
}

function switchGui() {
    if(forceDisplayGui || connected) {
        // display gui
        document.getElementById('connectionGui').style.display = 'none';
        document.getElementById('mainGui').style.display = 'block';

        initMainGuiEventListeners();
        refreshMainGui();
    } else {
        //display connection
        document.getElementById('connectionGui').style.display = 'block';
        document.getElementById('mainGui').style.display = 'none';

        initConnectionGuiListeners();
        refreshConnectionGui();

        initWebSocket();
    } 
}

// --------------- CONNECTION GUI ---------------------
function initConnectionGuiListeners() {
    document.getElementById('changeGatewayIpButton').addEventListener('click', onChangeGatewayIpButton);
}
function refreshConnectionGui() {
    if(!document.getElementById('gatewayIpInput').value) {
        document.getElementById('gatewayIpInput').value = gatewayIp;
    }
    document.getElementById('connectionMessage').innerHTML = `Try to connect to "ws://${gatewayIp}${websocketRoot}"`;
}
function onChangeGatewayIpButton() {
    gatewayIp = document.getElementById('gatewayIpInput').value;
    console.log(`onChangeGatewayIpButton : ${gatewayIp}`);

    localStorage.setItem('gatewayIp', gatewayIp);

    refreshConnectionGui();
    initWebSocket();
}

// --------------- MAIN GUI ---------------------
function initMainGuiEventListeners() {
    // mp3
    document.getElementById('volumeSlider').addEventListener('change', onVolumeSlider);
}

function refreshMainGui() {
    document.getElementById('volumeSlider').value = volume;
}

// -------------- ACTIONS --------------------------
function onVolumeSlider() {
    console.log(`onVolumeSlider : ${document.getElementById('volumeSlider').value}`);
    websocket.send(`setVolume:${document.getElementById('volumeSlider').value}`);
}

Complete code here : https://github.com/Akta3d/Akta3d_MP3_And_Led

If I comment the analogRead line, the html page can connect to the server, all work fine without volume potentiometer

Do you have an idea of this conflict ?

Pablo2048 commented 3 years ago

The ADC inside ESP SoC is used also for WiFi stuff IMHO. Just don't read the ADC in every loop - try to read it every say 30 - 50 ms...

Akta3d commented 3 years ago

@Pablo2048 Perfect, really thanks

JamesDelfini commented 3 years ago

The ADC inside ESP SoC is used also for WiFi stuff IMHO. Just don't read the ADC in every loop - try to read it every say 30 - 50 ms...

I was also wondering why my web server will not work suddenly when I try to read the analog pin. Thanks for this.