因为使用云服务有时候不可靠,那么离线控制就很重要。本文使用webserver实现本地网页控制。这样不需要再单独开发APP,有浏览器就可以控制。本文所有测试是靠ESP32。8266未测试。使用USE_8266控制。
核心代码如下:
html.h
#pragma once
const char *AutoConfigHTML = u8R"esp_html(
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF8">
<title>智能控制台</title>
</head>
<body style="font-size: 30px">
<style>
.inputText {
height: 38px;
font-size: 30px;
line-height: 30px;
padding-left: 15px;
border-radius: 10px;
background-color: #dff1f7;
border: 2;
}
.inputText:focus {
outline: none;
background-color: #d6e4eb;
}
.buttonText {
height: 38px;
font-size: 30px;
line-height: 30px;
padding-left: 15px;
border-radius: 10px;
background-color: #FE5E08;
border: none;
}
.buttonText:focus {
outline: none;
background-color: #FE5E08;
}
.buttonText:disabled {
background-color: #c9c7c6;
}
</style>
<center>
<form>
<input id="btn_test" type="button" class="buttonText" value="点我测试" onclick="config(this)"/>
<br/>
<label id="recvtxt"/>
</form>
</center>
<script language="javascript">
function config(sender) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4) {
if (xmlhttp.status == 200) {
document.getElementById("recvtxt").innerText = "设置成功";
}
else {
document.getElementById("recvtxt").innerText = "设置失败";
document.getElementById("btnsendconfig").disabled = false;
}
}
}
xmlhttp.ontimeout = function () {
window.location.href = "about:blank";
window.close();
}
xmlhttp.open("GET", "/Ctrl?btn_name=" + sender.id, true);
xmlhttp.timeout = 5000;
xmlhttp.send();
document.getElementById("btnsendconfig").disabled = true;
}
</script>
</body>
</html>
)esp_html";
webctrl.h
#include <atomic>
#include <thread>
#include <functional>
#include "html.h"
#ifndef AUTOCFGSSID
#define AUTOCFGSSID "ESP_WIFI"
#endif
#ifndef AUTOCFGPSW
#define AUTOCFGPSW "12345678"
#endif
#ifdef USE_8266
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
using TagWebSERVER = ESP8266WebServer;
#else
#include <WiFi.h>
#include <WebServer.h>
using TagWebSERVER = WebServer;
#endif
using FunWebServerCallback = std::function<bool(const char *)>;
class CWebControl
{
protected:
void HandleHtmlRoot()
{
m_ControlWebServer.send(200, "text/html", AutoConfigHTML);
}
void HandleHtmlContrl()
{
if (m_WebServerCallback)
{
bool bRet=m_WebServerCallback(m_ControlWebServer.arg("btn_name").c_str());
m_ControlWebServer.send(bRet?200:500, "text/html", m_ControlWebServer.arg("btn_name").c_str());
}
}
public:
CWebControl() : m_bRun(false)
{
}
void Init()
{
WiFi.mode(WIFI_AP_STA); // 双模式
WiFi.setAutoReconnect(true);
IPAddress ip, gateway, subnet;
ip.fromString("192.168.2.1");
gateway.fromString("192.168.2.1");
subnet.fromString("255.255.255.0");
WiFi.softAPConfig(ip, gateway, subnet);
WiFi.softAP(AUTOCFGSSID, AUTOCFGPSW);
m_ControlWebServer.on("/", std::bind(&CWebControl::HandleHtmlRoot, this));
m_ControlWebServer.on("/Ctrl", HTTP_GET, std::bind(&CWebControl::HandleHtmlContrl, this));
}
~CWebControl()
{
Stop();
}
void Stop()
{
m_bRun = false;
m_ControlWebServer.close();
if (m_LoopThread.joinable())
{
m_LoopThread.join();
}
}
void SetCallBack(FunWebServerCallback callback)
{
m_WebServerCallback = callback;
}
void Run()
{
Stop();
m_bRun = true;
m_ControlWebServer.begin(80);
m_LoopThread = std::thread(std::bind([&]
{
while (m_bRun)
{
m_ControlWebServer.handleClient();
} }));
}
private:
std::thread m_LoopThread;
TagWebSERVER m_ControlWebServer;
std::atomic_bool m_bRun;
FunWebServerCallback m_WebServerCallback;
};
调用方法如下
// 这里定义热点名和密码,定义一定要在#include "webCtrl.h"前面
//连接如下热点 在浏览器访问 192.168.2.1 即可打开控制页面。当然IP地址可以在webCtrl.h修改成你想要的。
//#define AUTOCFGSSID "ESP_WIFI"
//#define AUTOCFGPSW "12345678"
// 如果使用8266取消下行注释
// #define USE_8266
#include "webCtrl.h"
// 我这里使用的是ESP32 s3.当然其它型号也是代码通用。因为这里我的板子有一颗RGB。使用它测试。请根据需要修改
#ifndef USE_8266
#include "RGB.h"
RGB rgb(1, 48);//注意我买的板子是48脚。你的板子未必是
#endif
CWebControl g_WebControl;
bool WebCtrlCallBack(const char *name)
{
// btn_test这里需要修改HTML对应ID。我这里使用btn_test。添加按钮根据ID区分即可。
if (strcmp(name, "btn_test") == 0)
{
#ifndef USE_8266
static bool trunOn = false;
rgb.showRGB(trunOn = !trunOn, 0, 255, 100);
#endif
}
return true;
}
void setup()
{
// put your setup code here, to run once:
g_WebControl.Init();
g_WebControl.SetCallBack(std::bind(WebCtrlCallBack, std::placeholders::_1));
g_WebControl.Run();
#ifndef USE_8266
rgb.begin(50);
#endif
}
void loop()
{
// put your main code here, to run repeatedly:
}
工程代码下载: