1 (edited by Gunner 2021-11-17 23:53:27)

Topic: Dual Webpage and App controlled RGB LED

Sometimes (OK, lots of times) I do silly and mostly meaningless things just to see if I can.  This is one of those times.

After playing around with a Webserver/client sketch for ESP32, I figured I would try to see if I could integrate RemoteXY into the sketch as well. 

As the Webserver was using the WiFi, I setup RemoteXY with BLE... I wasn't sure if both would work at the same time or not... yes, I could have Googled that, but just jumping in was more fun. 

Short answer... yes, but you may need to connect the App very shortly after restarting the ESP32, else it sometimes seems to have problems grabbing the GUI info.  This is most likely due to the shared radio between WiFi and BT... At bootup, and because it starts first in the code, the BLE has time to send the GUI prior to the WiFi taking over.  And since after the GUI, the BLE commands are short and sweet, they get through in between WiFi timing.

In this forum, I am only including my Arduino sketch... you will need to go to this (unaffiliated with me) site to figure out the rest of the needed files for the SPIFFS, if you so chose such silliness as duplicating this project tongue  https://randomnerdtutorials.com/esp32-w … et-sliders

Meanwhile, what I did (and was what much of the challenge for me) was figure out how to write code that mixed and merged the incoming and outgoing processes so changes made on a web client or on the RemoteXY App, simultaneously updated each other, and of course both the physical LED and virtual one match colours, as shown here...

https://www.dropbox.com/s/2jhsrlosdpoubmn/App%20and%20Web%20controlled%20RGB%20sliders.jpg?dl=1

FYI, for the curious, long ago I made myself that RGBW test rig from a common anode RGB LED, a white LED (you can't see those wires) a dead household LED bulb casing and an empty wire spool.  Sometimes I just have too much time on my hands smile

Anyhow... Most of the input/output merger code is in the void loop() but a few lines that update the App sliders are in the rest of the code...and I commented those as needed.

Enjoy!

PS.  I found I needed to set the Partition Scheme to "Minimal SPIFFS (Large APPS with OTA)" with my particular MCU WEMOS LOLIN32 in order to get it to fit when flashing.

/*
   -- LEDs and Sliders - BLE Merger with WebServer --

   This source code of graphical user interface
   has been generated automatically by RemoteXY editor.
   To compile this code using RemoteXY library 2.4.3 or later version
   download by link http://remotexy.com/en/library/
   To connect using RemoteXY mobile app by link http://remotexy.com/en/download/
     - for ANDROID 4.7.12 or later version;
     - for iOS 1.4.7 or later version;

   This source code is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.
*/

//////////////////////////////////////////////
//        RemoteXY include library          //
//////////////////////////////////////////////

// RemoteXY select connection mode and include library
#define REMOTEXY_MODE__ESP32CORE_BLE

#include <RemoteXY.h>

// RemoteXY connection settings
#define REMOTEXY_BLUETOOTH_NAME "RGB & Web Server"


// RemoteXY configurate
#pragma pack(push, 1)
uint8_t RemoteXY_CONF[] =
{ 255, 3, 0, 3, 0, 33, 0, 11, 13, 0,
  4, 128, 9, 43, 27, 9, 1, 26, 65, 23,
  36, 7, 27, 27, 4, 128, 37, 43, 26, 9,
  12, 26, 4, 128, 64, 43, 27, 9, 6, 26
};

// this structure defines all the variables and events of your control interface
struct {

  // input variables
  int8_t slider_red; // =0..100 slider position
  int8_t slider_green; // =0..100 slider position
  int8_t slider_blue; // =0..100 slider position

  // output variables
  uint8_t RGB_LED_r; // =0..255 LED Red brightness
  uint8_t RGB_LED_g; // =0..255 LED Green brightness
  uint8_t RGB_LED_b; // =0..255 LED Blue brightness

  // other variable
  uint8_t connect_flag;  // =1 if wire connected, else =0

} RemoteXY;
#pragma pack(pop)

/////////////////////////////////////////////
//           END RemoteXY include          //
/////////////////////////////////////////////



/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-web-server-websocket-sliders/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "SPIFFS.h"
#include <Arduino_JSON.h>

// Replace with your network credentials
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Create a WebSocket object

AsyncWebSocket ws("/ws");
// Set LED GPIO
const int ledPin1 = 25; // Red
const int ledPin2 = 27; // Green
const int ledPin3 = 26; // Blue

String message = "";
String sliderValue1 = "0";
String sliderValue2 = "0";
String sliderValue3 = "0";

int dutyCycle1;
int dutyCycle2;
int dutyCycle3;

// setting PWM properties
const int freq = 5000;
const int ledChannel1 = 0;
const int ledChannel2 = 1;
const int ledChannel3 = 2;

const int resolution = 8;

//Json Variable to Hold Slider Values
JSONVar sliderValues;

//Get Slider Values
String getSliderValues() {
  sliderValues["sliderValue1"] = String(sliderValue1);
  sliderValues["sliderValue2"] = String(sliderValue2);
  sliderValues["sliderValue3"] = String(sliderValue3);

  String jsonString = JSON.stringify(sliderValues);
  return jsonString;
}

// Initialize SPIFFS
void initFS() {
  if (!SPIFFS.begin()) {
    Serial.println("An error has occurred while mounting SPIFFS");
  }
  else {
    Serial.println("SPIFFS mounted successfully");
  }
}

// Initialize WiFi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

void notifyClients(String sliverValues) {
  ws.textAll(sliverValues);
}

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;
    message = (char*)data;
    if (message.indexOf("1s") >= 0) {
      sliderValue1 = message.substring(2);
      dutyCycle1 = map(sliderValue1.toInt(), 0, 100, 0, 255);
      RemoteXY.slider_red = sliderValue1.toInt();  // RemoteXY command to update red slider
      //Serial.println(dutyCycle1);
      //Serial.print(getSliderValues());
      notifyClients(getSliderValues());
    }
    if (message.indexOf("2s") >= 0) {
      sliderValue2 = message.substring(2);
      dutyCycle2 = map(sliderValue2.toInt(), 0, 100, 0, 255);
      RemoteXY.slider_green = sliderValue2.toInt();  // RemoteXY command to update green slider
      //Serial.println(dutyCycle2);
      //Serial.print(getSliderValues());
      notifyClients(getSliderValues());
    }
    if (message.indexOf("3s") >= 0) {
      sliderValue3 = message.substring(2);
      dutyCycle3 = map(sliderValue3.toInt(), 0, 100, 0, 255);
      RemoteXY.slider_blue = sliderValue3.toInt();  // RemoteXY command to update blue slider
      //Serial.println(dutyCycle3);
      //Serial.print(getSliderValues());
      notifyClients(getSliderValues());
    }
    if (strcmp((char*)data, "getValues") == 0) {
      notifyClients(getSliderValues());
    }
  }
}
void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
  switch (type) {
    case WS_EVT_CONNECT:
      Serial.printf("WebSocket client #%u connected from %s\n", client->id(), 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);
}


void setup() {
  RemoteXY_Init (); // RemoteXT Command

  Serial.begin(115200);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  initFS();
  initWiFi();

  // configure LED PWM functionalitites
  ledcSetup(ledChannel1, freq, resolution);
  ledcSetup(ledChannel2, freq, resolution);
  ledcSetup(ledChannel3, freq, resolution);

  // attach the channel to the GPIO to be controlled
  ledcAttachPin(ledPin1, ledChannel1);
  ledcAttachPin(ledPin2, ledChannel2);
  ledcAttachPin(ledPin3, ledChannel3);


  initWebSocket();

  // Web Server Root URL
  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(SPIFFS, "/index.html", "text/html");
  });

  server.serveStatic("/", SPIFFS, "/");

  // Start server
  server.begin();

}

void loop() {
  RemoteXY_Handler(); // RemoteXY Command

  // Read RED slider value from RemoteXY, update web clients and physical LED to match
  int slideRed = sliderValue1.toInt();
  if (RemoteXY.slider_red != slideRed) {  // Check if RemoteXY slider has changed
    dutyCycle1 = map(RemoteXY.slider_red, 0, 100, 0, 255);  // Adjust Physical LED
    sliderValue1 = RemoteXY.slider_red;  // Adjust Web Client slider
    notifyClients(getSliderValues());  // Update Web Clients
  }

  // Read GREEN slider value from RemoteXY, update web clients and physical LED to match
  int slideGreen = sliderValue2.toInt();
  if (RemoteXY.slider_green != slideGreen) {  // Check if RemoteXY slider has changed
    dutyCycle2 = map(RemoteXY.slider_green, 0, 100, 0, 255);  // Adjust Physical LED
    sliderValue2 = RemoteXY.slider_green;  // Adjust Web Client slider
    notifyClients(getSliderValues());  // Update Web Clients
  }

  // Read BLUE slider value from RemoteXY, update web clients and physical LED to match
  int slideBlue = sliderValue3.toInt();
  if (RemoteXY.slider_blue != slideBlue) {  // Check if RemoteXY slider has changed
    dutyCycle3 = map(RemoteXY.slider_blue, 0, 100, 0, 255);  // Adjust Physical LED
    sliderValue3 = RemoteXY.slider_blue;  // Adjust Web Client slider
    notifyClients(getSliderValues());  // Update Web Clients
  }

  ledcWrite(ledChannel1, 255 - dutyCycle1); // -255 for Common Anode
  RemoteXY.RGB_LED_r = dutyCycle1; // RemoteXY command to update App Red LED

  ledcWrite(ledChannel2, 255 - dutyCycle2); // -255 for Common Anode
  RemoteXY.RGB_LED_g = dutyCycle2; // RemoteXY command to update App Green LED

  ledcWrite(ledChannel3, 255 - dutyCycle3); // -255 for Common Anode
  RemoteXY.RGB_LED_b = dutyCycle3; // RemoteXY command to update App Blue LED

  ws.cleanupClients();
}
"And voila, which is French for.......'and then I found out.'" - Ready Player One