简体   繁体   English

在 ESP32 客户端和服务器之间发送数据

[英]Sending Data Between ESP32 Client and Server

I am trying to create a simple web interface to control a NeoPixel strip from an ESP32 hosting a client over an access point.我正在尝试创建一个简单的 Web 界面来控制来自通过接入点托管客户端的 ESP32 的 NeoPixel 条带。 Every example I've found on the web so far demonstrates how you can toggle LED's ON/OFF by appending the state to the URL header and then using that info on the server-side to then call a function that toggles the physical LEDs, however, I'm trying to do something a little more unique.到目前为止,我在网上找到的每个示例都演示了如何通过将状态附加到 URL 标头然后在服务器端使用该信息来调用切换物理 LED 的函数来切换 LED 的开/关,然而,我正在尝试做一些更独特的事情。

I cannot find a way to pass the #hex value retrieved from my HTML color picker over the HTTP back to the server and use this to set the NEOPIXEL color then.我找不到将通过 HTTP 从我的 HTML 颜色选择器检索到的 #hex 值传递回服务器并使用它来设置 NEOPIXEL 颜色的方法。

One thing I'm doing differently than many examples out there is I'm letting the server handle the client by sending the HTML page using this function, which I understand takes my index.h file which contains the HTML code and sends it over the server to the client.我做的一件事与许多示例不同的是,我让服务器通过使用此函数发送 HTML 页面来处理客户端,据我所知,该函数获取包含 HTML 代码的 index.h 文件并将其发送到服务器到客户端。 But I'm not sure how to "reverse" this process, especially for a "text/variable"但我不确定如何“逆转”这个过程,尤其是对于“文本/变量”

This is my server code:这是我的服务器代码:

#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <Adafruit_NeoPixel.h>

//HTML code header for the web page
#include "index.h"

#define PIN 13

//Initialize the web client server
WebServer server(80);

//Initialize NeoPixels
Adafruit_NeoPixel strip = Adafruit_NeoPixel(12, PIN, NEO_GRB + NEO_KHZ800);

const char* ssid = "ESP32NeoPixelInterface";
const char* password = "password";

//temporary string to hold the HEX value of the color picker received from the web client
String header = "";

//Current time
unsigned long currentTime = millis();
//Previous time
unsigned long previousTime = 0;
//Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;

//===============================================================
// This routine is executed when you open its IP in browser
//===============================================================
void handleRoot() {
  String s = MAIN_page; //Read HTML contents
  server.send(200, "text/html", s); //Send web page
}

void UpdateNeoPixels() {

}

void setup(void) {
  Serial.begin(115200);
  Serial.println();
  Serial.println("Booting Sketch...");

  strip.begin();
  strip.setBrightness(25);

  //Connect to Wi-Fi network with SSID and password
  Serial.print("Setting AP (Access Point)…");
  //Remove the password parameter, if you want the AP (Access Point) to be open
  WiFi.softAP(ssid, password);

  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);

  //Start server
  server.on("/", handleRoot);      //This is display page
  server.begin();
  Serial.println("HTTP server started");

  //Set pixel #1 to green to show that an active access point connection has been made
  strip.setPixelColor(1, 100, 0, 0);
  strip.show();
}

//===============================================================
// This routine is executed when you open its IP in browser
//===============================================================
void loop(void) {
  server.handleClient();
}

and this is the header file for the client:这是客户端的头文件:

const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
  <head>
    <title>ESP32 NeoPixel Web Control</title>
  </head>
    <style>
      .button {
      display: inline;
      padding: 10px 10px;
      font-size: 2em;
      cursor: pointer;
      text-align: center;
      text-decoration: none;
      outline: none;
      color: #fff;
      background-color: #4CAF50;
      border: none;
      border-radius: 10px;
      box-shadow: 0px 2px 10px -2px rgba(0,0,0,0.5);
      }
      .button:hover {background-color: #3e8e41}
      .button:active {
      background-color: #3e8e41;
      box-shadow: 0px 2px 15px -2px rgba(0,0,0,0.75);
      transform: translateY(2px);
      }
      .p1 {
      font-family: "Monaco", monospace;
      color: white;
      font-size: 1em;
      }
      .container{ 
      position: absolute;
      }
      .center1{
      margin: auto;
      position: absolute;
      top: 50%;
      left: 50%;
      -ms-transform: translate(-50%, -50%);
      transform: translate(-50%, -50%);
      }
      .center2{
      margin: auto;
      position: absolute;
      top: 60%;
      left: 50%;
      -ms-transform: translate(-50%, -50%);
      transform: translate(-50%, -50%);
      }
    </style>
    <body bgcolor="#282c34">
      <h1 class="p1">This web page is hosted remotley by an ESP32 server, change the color of the LED NeoPixels using the color picker and press "SUBMIT".</STYLE></h1>
      <hr height="10px"/>
      <div class="containter">
        <div class="center1">
          <input type="color" id="myColor" value="#ff0080"> 
        </div>
        <div class="center2">
          <button class="button button1" align="center" onclick=SendColorValue()>SUBMIT</button>
        </div>
      </div>
    <script>
      function SendColorValue() {
        var x = document.getElementById("myColor");
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
        
        };
        //Send a request from client to server saying "hey update the color of the NeoPixels!"
        xhttp.open("POST", "ColorValue", true);
        xhttp.send(x.value);
      }
    </script>
    </body>
</html>
)=====";

I basically need to find a way to send x.value which is the color value retrieved from the color picker box back to the server and use this value to set the neopixel color.我基本上需要找到一种方法将 x.value (即从颜色选择器框中检索到的颜色值)发送回服务器,并使用该值来设置 neopixel 颜色。

Most examples I've seen only deal with sending "boolean" type data to the server from the client such as this:我见过的大多数示例只处理从客户端向服务器发送“布尔”类型的数据,例如:

// turns the GPIOs on and off
if (header.indexOf("GET /26/on") >= 0) {
  Serial.println("GPIO 26 on");
  output26State = "on";
  digitalWrite(output26, HIGH);
} else if (header.indexOf("GET /26/off") >= 0) {
  Serial.println("GPIO 26 off");
  output26State = "off";
  digitalWrite(output26, LOW);
}

For reference, this is what my client-side looks like:作为参考,这是我的客户端的样子: esp客户端

For processing the POST route you send from your client you need something on the server like:为了处理您从客户端发送的 POST 路由,您需要在服务器上安装一些东西,例如:

 server.on("/ColorValue", HTTP_POST, []() { ... });

then you have to process the argument (the hex value)那么你必须处理参数(十六进制值)

String newColorValue = server.arg("ColorValue");

hand it over to a routine for splitting the hex and setting the Led将其交给一个例程来拆分十六进制并设置 LED

setLedColor(newColorValue);

and respond to the client like并像回复客户一样

server.send(200, "text/plain", "Color changed");

so the whole thing would look like:所以整个事情看起来像:

server.on("/ColorValue", HTTP_POST, []() {
  String newColorValue = server.arg("ColorValue");
  setLedColor(newColorValue);
  server.send(200, "text/plain", "Color changed");
});

The sub-routine setLedColor looks something like子例程 setLedColor 看起来像

void setLedColor (String rgbHexValue) {
  char hexValue[3] =  {'\0'};
  uint8_t tenV;
  uint8_t oneV;
  // split and convert the String to uint8_t
  // code -> get first two letters via substring, process and convert to uint8_t
  rgbHexValue.substring(0, 2).toCharArray(hexValue, 2);
  tenV = (hexValue[0] <= '9') ? hexValue[0] - '0' : hexValue[0] - '7';
  oneV = (hexValue[1] <= '9') ? hexValue[1] - '0' : hexValue[1] - '7';
  uint8_t greenValue = (16 * tenV) + oneV;
  //pseudocode pretty much the same as above changes in the comments
  uint8_t redValue = ... //pseudocode -> second two letters via rgbHexValue.substring(2, 4) and from hex to uint see above
  uint8_t blueValue = ... //pseudocode -> last two letters via rgbHexValue.substring(4) and from hex to uint see above
  // Set pixel #1 to new color
  strip.setPixelColor(1, greenValue, redValue, blueValue); // check if correct
  strip.show();
}

Comments (also for other readers): I personally do not use String class with ESP8266/ESP32 because on the long run (which is sometimes a few minutes) it defragments the memory and crashes the device.评论(也适用于其他读者):我个人不使用ESP8266/ESP32 的 String 类,因为从长远来看(有时是几分钟)它会整理内存并使设备崩溃。 So you should learn from the start to use char arrays and char handling for stable usage so I would propose the following code:所以你应该从一开始就学习使用 char 数组和 char 处理来稳定使用,所以我建议以下代码:

Define a global char array before setup():在 setup() 之前定义一个全局字符数组:

static char newColorValue[7] =  {'\0'}; 

and getting the value from the client like并从客户那里获得价值

strcpy(newColorValue, webServer.arg("ColorValue").c_str());

which leads to the following route:这导致以下路线:

server.on("/ColorValue", HTTP_POST, []() {
  strcpy(newColorValue, webServer.arg("ColorValue").c_str());
  setLedColor(newColorValue);
  server.send(200, "text/plain", "Color changed");
}); 

and the setLedColor is then defined as follows:然后 setLedColor 定义如下:

void setLedColor () { // Convert routine for rgbHex to uint values
  char hexValue[3] =  {'\0'}; // holds a 2 digit hex value eg A9
  uint8_t tenV;    // first digit value eg A
  uint8_t oneV;    // second digit value eg 9
  // split and process the char array newColorValue
  // split and convert the first two digits
  strncpy(hexValue,newColorValue, 2); 
  tenV = (hexValue[0] <= '9') ? hexValue[0] - '0' : hexValue[0] - '7';
  oneV = (hexValue[1] <= '9') ? hexValue[1] - '0' : hexValue[1] - '7';
  uint8_t greenValue = (16 * tenV) + oneV;

  // second two digits
  strncpy(hexValue,newColorValue + 2, 2);
  ...
  uint8_t redValue = ...

  // Last two digits
  strncpy(hexValue,newColorValue + 4, 2);
  ...
  uint8_t blueValue = ... 
}

Hope this solution helps your project - and remember " Strings are evil " ;-)希望这个解决方案对您的项目有所帮助 - 并记住“字符串是邪恶的”;-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM