2025-11-22

使用 ESP32-S2-WROOM 作為 WiFi USB HID

在下曾經使用 ESP32-S3 0.42in OLED 來製作模仿 O.MG 的 USB HID 裝置來無線控制宿主系統(主要是電腦)
但 ESP32-S3 0.42in OLED 與大多數 微控制器開發板 相同,都是使用 USB插口,即是需要使用 USB線 才能連接
在下希望能找到一款不需要額外工具便能夠直接安裝到 USB插口 的 微控制器開發板 來達到效果

外觀

結果確實找到其中一款使用 USB Type-A 插頭的 微控制器開發板
而且同樣是 ESP32系列 的 ESP32-S2

查閱資料後,發現 ESP32-S2 同樣支援 USB HID ,因此可以製作類似

使用 ESP32-S2-WROOM 的開發板 的正面

ESP32-S2-WROOM 的晶片在金屬殼下保護著,不過引腳則引出到外殼外
但引腳間距並非 0.1寸 或 2.54毫米 ,因此不能使用一般引腳座

板載LED ,與 IO17 連接,高電壓時亮著

按壓按鈕,與 IO0 連接,按下時接地,按下時通電可載入至 起動模式

天線焊接位,能焊接 IPEX天線,但預設是沒有焊接

ESP32-S2-WROOM 開發板 的背面

ESP32-S2-WROOM 的背面標示前方向引腳的名稱

雖然 ESP32-S2-WROOM 有標示引腳,但引腳的距離很少,要安全地引出引腳使用並不容易

使用 USB Type-A 插頭,方便連接到電腦

測試閃動效果

測試

#include <WiFi.h>
#include <WebServer.h>
#include <USB.h>
#include <USBHIDKeyboard.h>
#include <USBHIDMouse.h>
#include <USBHIDConsumerControl.h>
#include <WiFiManager.h>
#include <ESPmDNS.h>
#define BTN 0
#define LED 17
#define ACTION_PRESS 1
#define ACTION_RELEASE 2
#define ACTION_WRITE 0
#define DEFAULT_SSID "ESP32-S2 WiFi USB HID"
#define DEFAULT_PASS "12345678"
#define DEFAULT_HOST "esp32-s2-wifi-usb-hid"
#define HTML_DEFAULT "<!DOCTYPE html>\n\
<html lang=\"en\">\n\
	<head>\n\
		<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\
		<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>\n\
		<title>ESP32-S2 WiFi USB HID</title>\n\
		<script>\n\
window.addEventListener(\"load\", function(loadEvent) {\n\
	document.getElementById(\"add\").addEventListener(\"click\", function(clickEvent) {\n\
		var actionSelect = document.getElementById(\"action\");\n\
		var keyboardSelect = document.getElementById(\"keyboard\");\n\
		var mouseSelect = document.getElementById(\"mouse\");\n\
		var otherText = document.getElementById(\"other\");\n\
		var dataTextArea = document.form.data;\n\
		var tempString = actionSelect.value;\n\
		if (actionSelect.value == \"keyboard.press\" || actionSelect.value == \"keyboard.release\" || actionSelect.value == \"keyboard.write\") {\n\
			tempString += \" \" + keyboardSelect.value;\n\
		} else if (actionSelect.value == \"mouse.press\" || actionSelect.value == \"mouse.release\" || actionSelect.value == \"mouse.click\") {\n\
			tempString += \" \" + mouseSelect.value;\n\
		} else if (actionSelect.value == \"keyboard.print\" || actionSelect.value == \"keyboard.println\" || actionSelect.value == \"mouse.set-x\" || actionSelect.value == \"mouse.set-y\" || actionSelect.value == \"mouse.move-x\" || actionSelect.value == \"mouse.move-y\" || actionSelect.value == \"delay.us\" || actionSelect.value == \"delay.ms\" || actionSelect.value == \"delay.s\" || actionSelect.value == \"delay.m\" || actionSelect.value == \"delay.h\" || actionSelect.value == \"script.repeat\") {\n\
			tempString += \" \" + otherText.value;\n\
		}\n\
		dataTextArea.value += (dataTextArea.value.length > 0 ? \"\\n\" : \"\") + tempString;\n\
		otherText.value = \"\";\n\
		dataTextArea.selectionStart = dataTextArea.value.length;\n\
		dataTextArea.selectionEnd = dataTextArea.value.length;\n\
	});\n\
});\n\
		</script>\n\
	</head>\n\
	<body>\n\
		<table style=\"border-collapse: collapse;\" border=\"1\" cellpadding=\"5\" cellspacing=\"5\">\n\
			<tbody>\n\
				<tr>\n\
					<td>Action</td>\n\
					<td>\n\
<select id=\"action\">\n\
	<optgroup label=\"Keyboard\">\n\
		<option value=\"keyboard.release-all\">Release all Keyboard keys</option>\n\
		<option value=\"keyboard.press\">Hold the Keyboard key (Refer to Keyboard Event)</option>\n\
		<option value=\"keyboard.release\">Release the Keyboard key (Refer to Keyboard Event)</option>\n\
		<option value=\"keyboard.write\">Press and Release the Keyboard key (Refer to Keyboard Event)</option>\n\
		<option value=\"keyboard.print\">Type Text (Refer to Other)</option>\n\
		<option value=\"keyboard.println\">Type Text with auto Enter (Refer to Other)</option>\n\
	</optgroup>\n\
	<optgroup label=\"Mouse\">\n\
		<option value=\"mouse.release-all\">Release all Mouse keys</option>\n\
		<option value=\"mouse.press\">Hold the Mouse key (Refer to Mouse Event)</option>\n\
		<option value=\"mouse.release\">Release the Mouse key (Refer to Mouse Event)</option>\n\
		<option value=\"mouse.click\">Click the Mouse key (Refer to Mouse Event)</option>\n\
		<option value=\"mouse.set-x\">Set the cursor to the target X position (Refer to Other)</option>\n\
		<option value=\"mouse.set-y\">Set the cursor to the target Y position (Refer to Other)</option>\n\
		<option value=\"mouse.move-x\">Move the cursor from the target X position (Refer to Other)</option>\n\
		<option value=\"mouse.move-y\">Move the cursor from the target Y position (Refer to Other)</option>\n\
	</optgroup>\n\
	<optgroup label=\"Delay\">\n\
		<option value=\"delay.us\">Delay microsecond (Refer to Other)</option>\n\
		<option value=\"delay.ms\">Delay millisecond (Refer to Other)</option>\n\
		<option value=\"delay.s\">Delay second (Refer to Other, Blink every seconds)</option>\n\
		<option value=\"delay.m\">Delay minute (Refer to Other, Blink every seconds)</option>\n\
		<option value=\"delay.h\">Delay hour (Refer to Other, Blink every seconds)</option>\n\
	</optgroup>\n\
	<optgroup label=\"Volume\">\n\
		<option value=\"volume.toggle-mute\">Toogle Mute/Unmute</option>\n\
		<option value=\"volume.up\">Increase Volume by 1</option>\n\
		<option value=\"volume.down\">Decrease Volume by 1</option>\n\
	</optgroup>\n\
	<optgroup label=\"Brightness\">\n\
		<option value=\"brightness.up\">Increase Brightness by 1</option>\n\
		<option value=\"brightness.down\">Decrease Brightness by 1</option>\n\
	</optgroup>\n\
	<optgroup label=\"Other\">\n\
		<option value=\"script.repeat\">Repeat Previous Scripts Until Other Repeat (Refer to Other)</option>\n\
	</optgroup>\n\
</select>\n\
					</td>\n\
				</tr>\n\
				<tr>\n\
					<td>Keyboard Event</td>\n\
					<td>\n\
<select id=\"keyboard\">\n\
	<optgroup label=\"Control Character\">\n\
		<option value=\"ctrl\">Left Ctrl / Left Control</option>\n\
		<option value=\"shift\">Left Shift</option>\n\
		<option value=\"alt\">Left Alt / Left Option</option>\n\
		<option value=\"gui\">Left GUI / Left Windows / Left Command</option>\n\
		<option value=\"ctrl-right\">Right Ctrl / Right Control</option>\n\
		<option value=\"shift-right\">Right Shift</option>\n\
		<option value=\"alt-right\">Right Alt / Right Option</option>\n\
		<option value=\"gui-right\">Right GUI / Right Windows / Right Command</option>\n\
		<option value=\"enter\">Enter / Return</option>\n\
		<option value=\"esc\">Esc / Escape</option>\n\
		<option value=\"backspace\">Backspace</option>\n\
		<option value=\"caps-lock\">Caps Lock</option>\n\
		<option value=\"f1\">F1</option>\n\
		<option value=\"f2\">F2</option>\n\
		<option value=\"f3\">F3</option>\n\
		<option value=\"f4\">F4</option>\n\
		<option value=\"f5\">F5</option>\n\
		<option value=\"f\">F6</option>\n\
		<option value=\"f71\">F7</option>\n\
		<option value=\"f8\">F8</option>\n\
		<option value=\"f9\">F9</option>\n\
		<option value=\"f10\">F10</option>\n\
		<option value=\"f11\">F11</option>\n\
		<option value=\"f12\">F12</option>\n\
		<option value=\"print-screen\">Print Screen</option>\n\
		<option value=\"scroll-lock\">Scroll Lock</option>\n\
		<option value=\"pause\">Pause / Break</option>\n\
		<option value=\"insert\">Insert</option>\n\
		<option value=\"home\">Home</option>\n\
		<option value=\"page-up\">Page Up</option>\n\
		<option value=\"delete\">Delete / Del</option>\n\
		<option value=\"end\">End</option>\n\
		<option value=\"page-down\">Page Down</option>\n\
		<option value=\"arrow-right\">Right Arrow</option>\n\
		<option value=\"arrow-left\">Left Arrow</option>\n\
		<option value=\"arrow-down\">Down Arrow</option>\n\
		<option value=\"arrow-up\">Up Arrow</option>\n\
		<option value=\"num-lock\">Num Lock</option>\n\
		<option value=\"menu\">Menu</option>\n\
		<option value=\"halt\">Halt / Power Off</option>\n\
		<option value=\"f13\">F13</option>\n\
		<option value=\"f14\">F14</option>\n\
		<option value=\"f15\">F15</option>\n\
		<option value=\"f16\">F16</option>\n\
		<option value=\"f17\">F17</option>\n\
		<option value=\"f18\">F18</option>\n\
		<option value=\"f19\">F19</option>\n\
		<option value=\"f20\">F20</option>\n\
		<option value=\"f21\">F21</option>\n\
		<option value=\"f22\">F22</option>\n\
		<option value=\"f23\">F23</option>\n\
		<option value=\"f24\">F24</option>\n\
	</optgroup>\n\
	<optgroup label=\"Ascii Character\">\n\
		<option value=\"a\">Small Letter A</option>\n\
		<option value=\"b\">Small Letter B</option>\n\
		<option value=\"c\">Small Letter C</option>\n\
		<option value=\"d\">Small Letter D</option>\n\
		<option value=\"e\">Small Letter E</option>\n\
		<option value=\"f\">Small Letter F</option>\n\
		<option value=\"g\">Small Letter G</option>\n\
		<option value=\"h\">Small Letter H</option>\n\
		<option value=\"i\">Small Letter I</option>\n\
		<option value=\"j\">Small Letter J</option>\n\
		<option value=\"k\">Small Letter K</option>\n\
		<option value=\"l\">Small Letter L</option>\n\
		<option value=\"m\">Small Letter M</option>\n\
		<option value=\"n\">Small Letter N</option>\n\
		<option value=\"o\">Small Letter O</option>\n\
		<option value=\"p\">Small Letter P</option>\n\
		<option value=\"q\">Small Letter Q</option>\n\
		<option value=\"r\">Small Letter R</option>\n\
		<option value=\"s\">Small Letter S</option>\n\
		<option value=\"t\">Small Letter T</option>\n\
		<option value=\"u\">Small Letter U</option>\n\
		<option value=\"v\">Small Letter V</option>\n\
		<option value=\"w\">Small Letter W</option>\n\
		<option value=\"x\">Small Letter X</option>\n\
		<option value=\"y\">Small Letter Y</option>\n\
		<option value=\"z\">Small Letter Z</option>\n\
		<option value=\"1\">Number 1</option>\n\
		<option value=\"2\">Number 2</option>\n\
		<option value=\"3\">Number 3</option>\n\
		<option value=\"4\">Number 4</option>\n\
		<option value=\"5\">Number 5</option>\n\
		<option value=\"6\">Number 6</option>\n\
		<option value=\"7\">Number 7</option>\n\
		<option value=\"8\">Number 8</option>\n\
		<option value=\"9\">Number 9</option>\n\
		<option value=\"0\">Number 0</option>\n\
		<option value=\" \">Tab</option>\n\
		<option value=\" \">Space</option>\n\
		<option value=\"-\">Minus</option>\n\
		<option value=\"=\">Equal</option>\n\
		<option value=\"[\">[</option>\n\
		<option value=\"]\">]</option>\n\
		<option value=\"\\\">\\</option>\n\
		<option value=\"¥\">¥</option>\n\
		<option value=\";\">;</option>\n\
		<option value=\"'\">'</option>\n\
		<option value=\"`\">`</option>\n\
		<option value=\",\">,</option>\n\
		<option value=\".\">.</option>\n\
		<option value=\"/\">/</option>\n\
	</optgroup>\n\
	<optgroup label=\"Num Pad Character\">\n\
		<option value=\"np/\">Num Pad /</option>\n\
		<option value=\"np*\">Num Pad *</option>\n\
		<option value=\"np-\">Num Pad -</option>\n\
		<option value=\"np+\">Num Pad +</option>\n\
		<option value=\"npe\">Num Pad Enter</option>\n\
		<option value=\"np1\">Num Pad 1</option>\n\
		<option value=\"np2\">Num Pad 2</option>\n\
		<option value=\"np3\">Num Pad 3</option>\n\
		<option value=\"np4\">Num Pad 4</option>\n\
		<option value=\"np5\">Num Pad 5</option>\n\
		<option value=\"np6\">Num Pad 6</option>\n\
		<option value=\"np7\">Num Pad 7</option>\n\
		<option value=\"np8\">Num Pad 8</option>\n\
		<option value=\"np9\">Num Pad 9</option>\n\
		<option value=\"np0\">Num Pad 0</option>\n\
		<option value=\"np.\">Num Pad .</option>\n\
		<option value=\"np<\">Num Pad &lt;</option>\n\
		<option value=\"np=\">Num Pad =</option>\n\
	</optgroup>\n\
</select>\n\
					</td>\n\
				</tr>\n\
				<tr>\n\
					<td>Mouse Event</td>\n\
					<td>\n\
<select id=\"mouse\">\n\
	<option value=\"left\">Left</option>\n\
	<option value=\"middle\">Middle</option>\n\
	<option value=\"right\">Right</option>\n\
</select>\n\
					</td>\n\
				</tr>\n\
				<tr>\n\
					<td>Other</td>\n\
					<td>\n\
<input id=\"other\" type=\"text\"/>\n\
					</td>\n\
				</tr>\n\
				<tr>\n\
					<td colspan=\"2\">\n\
<input id=\"add\" type=\"button\" value=\"Add Action\"/>\n\
					</td>\n\
				</tr>\n\
			</tbody>\n\
		</table>\n\
		<form name=\"form\" action=\"/hid\" method=\"post\" onsubmit=\"return window.confirm('Are you sure to start sending the USB HID command?');\">\n\
			<div><textarea name=\"data\" rows=\"10\" cols=\"50\"></textarea></div>\n\
			<div><input type=\"submit\"/><input type=\"reset\"/></div>\n\
		</form>\n\
	</body>\n\
</html>"
WebServer server(80);
USBHIDKeyboard Keyboard;
USBHIDMouse Mouse;
USBHIDConsumerControl ConsumerControl;
byte keyboardMap(String name) {
	byte key = 0;
	if (name == "ctrl" || name == "control" || name == "ctrl-left" || name == "control-left") {
		key = 0x80;
	} else if (name == "shift" || name == "shift-left") {
		key = 0x81;
	} else if (name == "alt" || name == "option" || name == "alt-left" || name == "option-left") {
		key = 0x82;
	} else if (name == "gui" || name == "meta" || name == "super" || name == "hyper" || name == "win" || name == "windows" || name == "cmd" || name == "command" || name == "gui-left" || name == "meta-left" || name == "super-left" || name == "hyper-left" || name == "win-left" || name == "windows-left" || name == "cmd-left" || name == "command-left") {
		key = 0x83;
	} else if (name == "ctrl-right" || name == "control-right") {
		key = 0x84;
	} else if (name == "shift-right") {
		key = 0x85;
	} else if (name == "alt-right" || name == "option-right") {
		key = 0x86;
	} else if (name == "gui-right" || name == "meta-right" || name == "super-right" || name == "hyper-right" || name == "win-right" || name == "windows-right" || name == "cmd-right" || name == "command-right") {
		key = 0x87;
	} else if (name == "a") {
		key = 0x8C;
	} else if (name == "b") {
		key = 0x8D;
	} else if (name == "c") {
		key = 0x8E;
	} else if (name == "d") {
		key = 0x8F;
	} else if (name == "e") {
		key = 0x90;
	} else if (name == "f") {
		key = 0x91;
	} else if (name == "g") {
		key = 0x92;
	} else if (name == "h") {
		key = 0x93;
	} else if (name == "i") {
		key = 0x94;
	} else if (name == "j") {
		key = 0x95;
	} else if (name == "k") {
		key = 0x96;
	} else if (name == "l") {
		key = 0x97;
	} else if (name == "m") {
		key = 0x98;
	} else if (name == "n") {
		key = 0x99;
	} else if (name == "o") {
		key = 0x9A;
	} else if (name == "p") {
		key = 0x9B;
	} else if (name == "q") {
		key = 0x9C;
	} else if (name == "r") {
		key = 0x9D;
	} else if (name == "s") {
		key = 0x9E;
	} else if (name == "t") {
		key = 0x9F;
	} else if (name == "u") {
		key = 0xA0;
	} else if (name == "v") {
		key = 0xA1;
	} else if (name == "w") {
		key = 0xA2;
	} else if (name == "x") {
		key = 0xA3;
	} else if (name == "y") {
		key = 0xA4;
	} else if (name == "z") {
		key = 0xA5;
	} else if (name == "1") {
		key = 0xA6;
	} else if (name == "2") {
		key = 0xA7;
	} else if (name == "3") {
		key = 0xA8;
	} else if (name == "4") {
		key = 0xA9;
	} else if (name == "5") {
		key = 0xAA;
	} else if (name == "6") {
		key = 0xAB;
	} else if (name == "7") {
		key = 0xAC;
	} else if (name == "8") {
		key = 0xAD;
	} else if (name == "9") {
		key = 0xAE;
	} else if (name == "0") {
		key = 0xAF;
	} else if (name == "enter" || name == "return") {
		key = 0xB0;
	} else if (name == "escape" || name == "esc") {
		key = 0xB1;
	} else if (name == "backspace") {
		key = 0xB2;
	} else if (name == "	") {
		key = 0xB3;
	} else if (name == " ") {
		key = 0xB4;
	} else if (name == "-") {
		key = 0xB5;
	} else if (name == "=") {
		key = 0xB6;
	} else if (name == "[") {
		key = 0xB7;
	} else if (name == "]") {
		key = 0xB8;
	} else if (name == "\\") {
		key = 0xB9;
	} else if (name == "¥") {
		key = 0xBA;
	} else if (name == ";") {
		key = 0xBB;
	} else if (name == "'") {
		key = 0xBC;
	} else if (name == "`") {
		key = 0xBD;
	} else if (name == ",") {
		key = 0xBE;
	} else if (name == ".") {
		key = 0xBF;
	} else if (name == "/") {
		key = 0xC0;
	} else if (name == "caps-lock") {
		key = 0xC1;
	} else if (name == "f1") {
		key = 0xC2;
	} else if (name == "f2") {
		key = 0xC3;
	} else if (name == "f3") {
		key = 0xC4;
	} else if (name == "f4") {
		key = 0xC5;
	} else if (name == "f5") {
		key = 0xC6;
	} else if (name == "f6") {
		key = 0xC7;
	} else if (name == "f7") {
		key = 0xC8;
	} else if (name == "f8") {
		key = 0xC9;
	} else if (name == "f9") {
		key = 0xCA;
	} else if (name == "f10") {
		key = 0xCB;
	} else if (name == "f11") {
		key = 0xCC;
	} else if (name == "f12") {
		key = 0xCD;
	} else if (name == "print-screen") {
		key = 0xCE;
	} else if (name == "scroll-lock") {
		key = 0xCF;
	} else if (name == "pause" || name == "break") {
		key = 0xD0;
	} else if (name == "insert") {
		key = 0xD1;
	} else if (name == "home") {
		key = 0xD2;
	} else if (name == "page-up") {
		key = 0xD3;
	} else if (name == "delete" || name == "del") {
		key = 0xD4;
	} else if (name == "end") {
		key = 0xD5;
	} else if (name == "page-down") {
		key = 0xD6;
	} else if (name == "arrow-right") {
		key = 0xD7;
	} else if (name == "arrow-left") {
		key = 0xD8;
	} else if (name == "arrow-down") {
		key = 0xD9;
	} else if (name == "arrow-up") {
		key = 0xDA;
	} else if (name == "num-lock") {
		key = 0xDB;
	} else if (name == "np/") {
		key = 0xDC;
	} else if (name == "np*") {
		key = 0xDD;
	} else if (name == "np-") {
		key = 0xDE;
	} else if (name == "np+") {
		key = 0xDF;
	} else if (name == "npe") {
		key = 0xE0;
	} else if (name == "np1") {
		key = 0xE1;
	} else if (name == "np2") {
		key = 0xE2;
	} else if (name == "np3") {
		key = 0xE3;
	} else if (name == "np4") {
		key = 0xE4;
	} else if (name == "np5") {
		key = 0xE5;
	} else if (name == "np6") {
		key = 0xE6;
	} else if (name == "np7") {
		key = 0xE7;
	} else if (name == "np8") {
		key = 0xE8;
	} else if (name == "np9") {
		key = 0xE9;
	} else if (name == "np0") {
		key = 0xEA;
	} else if (name == "np.") {
		key = 0xEB;
	} else if (name == "np<") {
		key = 0xEC;
	} else if (name == "menu") {
		key = 0xED;
	} else if (name == "halt" || name == "shutdown" || name == "power-off") {
		key = 0xEE;
	} else if (name == "np=") {
		key = 0xEF;
	} else if (name == "f13") {
		key = 0xF0;
	} else if (name == "f14") {
		key = 0xF1;
	} else if (name == "f15") {
		key = 0xF2;
	} else if (name == "f16") {
		key = 0xF3;
	} else if (name == "f17") {
		key = 0xF4;
	} else if (name == "f18") {
		key = 0xF5;
	} else if (name == "f19") {
		key = 0xF6;
	} else if (name == "f20") {
		key = 0xF7;
	} else if (name == "f21") {
		key = 0xF8;
	} else if (name == "f22") {
		key = 0xF9;
	} else if (name == "f23") {
		key = 0xFA;
	} else if (name == "f24") {
		key = 0xFB;
	}
	return key;
}
void keyboardAction(byte key, byte action) {
	if (action == ACTION_PRESS) {
		Keyboard.press(key);
	} else if (action == ACTION_RELEASE) {
		Keyboard.release(key);
	} else {
		Keyboard.write(key);
	}
}
byte mouseMap(String name) {
	byte key = 0;
	if (name == "left") {
		key = MOUSE_LEFT;
	} else if (name == "middle") {
		key = MOUSE_MIDDLE;
	} else if (name == "right") {
		key = MOUSE_RIGHT;
	}
	return key;
}
void mouseAction(byte key, byte action) {
	if (action == ACTION_PRESS) {
		Mouse.press(key);
	} else if (action == ACTION_RELEASE) {
		Mouse.release(key);
	} else {
		Mouse.click(key);
	}
}
void delayS(unsigned int value) {
	for (unsigned int i = 0; i < value; i++) {
		digitalWrite(LED, LOW);
		delay(500);
		digitalWrite(LED, HIGH);
		delay(500);
	}
}
void delayM(unsigned int value) {
	for (unsigned int i = 0; i < 60; i++) {
		delayS(value);
	}
}
void delayH(unsigned int value) {
	for (unsigned int i = 0; i < 60; i++) {
		delayM(value);
	}
}
void mouseMove(char axis, int value, byte multiple) {
	int position = ((value < 0) ? -multiple : multiple);
	value = abs(value);
	for (unsigned int i = 0; i < value; i++) {
		if (axis == 'x') {
			Mouse.move(position, 0, 0);
		} else if (axis == 'y') {
			Mouse.move(0, position, 0);
		}
	}
}
void runScript(String data) {
	if (data.indexOf("\r") > -1) {
		data.replace("\r", "");
	}
	if (data.indexOf("\n\n") > -1) {
		data.replace("\n\n", "\n");
	}
	String backup = "";
	while (data.length() > 0) {
		int index = data.indexOf("\n");
		String line = (index > -1 ? data.substring(0, index) : data.substring(0));
		data = (index > -1 ? data.substring(index + 1) : "");
		index = line.indexOf(" ");
		String command = (index > -1 ? line.substring(0, index) : line.substring(0));
		if (command == "keyboard.release-all") {
			backup += "\n" + line;
			Keyboard.releaseAll();
		} else if (command == "mouse.release-all") {
			backup += "\n" + line;
			Mouse.release(MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT);
		} else if (command == "volume.toggle-mute") {
			backup += "\n" + line;
			ConsumerControl.press(CONSUMER_CONTROL_MUTE);
			ConsumerControl.release();
		} else if (command == "volume.up") {
			backup += "\n" + line;
			ConsumerControl.press(CONSUMER_CONTROL_VOLUME_INCREMENT);
			ConsumerControl.release();
		} else if (command == "volume.down") {
			backup += "\n" + line;
			ConsumerControl.press(CONSUMER_CONTROL_VOLUME_DECREMENT);
			ConsumerControl.release();
		} else if (command == "brightness.up") {
			backup += "\n" + line;
			ConsumerControl.press(CONSUMER_CONTROL_BRIGHTNESS_INCREMENT);
			ConsumerControl.release();
		} else if (command == "brightness.down") {
			backup += "\n" + line;
			ConsumerControl.press(CONSUMER_CONTROL_BRIGHTNESS_DECREMENT);
			ConsumerControl.release();
		} else {
			String value = (index > -1 ? line.substring(index + 1) : "");
			if (command == "delay.us") {
				backup += "\n" + line;
				index = value.toInt();
				delayMicroseconds(index);
			} else if (command == "delay.ms") {
				backup += "\n" + line;
				index = value.toInt();
				delay(index);
			} else if (command == "delay.s") {
				backup += "\n" + line;
				index = value.toInt();
				delayS(index);
			} else if (command == "delay.m") {
				backup += "\n" + line;
				index = value.toInt();
				delayM(index);
			} else if (command == "delay.h") {
				backup += "\n" + line;
				index = value.toInt();
				delayH(index);
			} else if (command == "keyboard.print") {
				backup += "\n" + line;
				Keyboard.print(value);
			} else if (command == "keyboard.println") {
				backup += "\n" + line;
				Keyboard.println(value);
			} else if (command == "keyboard.press" || command == "keyboard.release" || command == "keyboard.write") {
				byte key = keyboardMap(value);
				byte action = (command == "keyboard.press" ? ACTION_PRESS : (command == "keyboard.release" ? ACTION_RELEASE : ACTION_WRITE));
				if (key > 0) {
					backup += "\n" + line;
					keyboardAction(key, action);
				}
			} else if (command == "mouse.set-x") {
				backup += "\n" + line;
				index = value.toInt();
				mouseMove('x', index, -100);
				mouseMove('x', index, 1);
			} else if (command == "mouse.set-y") {
				backup += "\n" + line;
				index = value.toInt();
				mouseMove('y', index, -100);
				mouseMove('y', index, 1);
			} else if (command == "mouse.move-x") {
				backup += "\n" + line;
				index = value.toInt();
				mouseMove('x', index, 1);
			} else if (command == "mouse.move-y") {
				backup += "\n" + line;
				index = value.toInt();
				mouseMove('y', index, 1);
			} else if (command == "mouse.press" || command == "mouse.release" || command == "mouse.click") {
				byte key = mouseMap(value);
				byte action = (command == "mouse.press" ? ACTION_PRESS : (command == "mouse.release" ? ACTION_RELEASE : ACTION_WRITE));
				if (key > 0) {
					backup += "\n" + line;
					mouseAction(key, action);
				}
			} else if (command == "script.repeat") {
				index = value.toInt();
				for (unsigned int n = 0; n < index; n++) {
					runScript(backup);
				}
				backup = "";
			}
		}
	}
}
void setup() {
	Serial.begin(115200);
	pinMode(LED, OUTPUT);
	for (byte i = 0; i < 50; i++) {
		digitalWrite(LED, !digitalRead(LED));
		delay(100);
	}
	digitalWrite(LED, HIGH);
	pinMode(BTN, INPUT_PULLUP);
	attachInterrupt(digitalPinToInterrupt(BTN), []() {
		ESP.restart();
	}, FALLING);
	WiFiManager wm;
	wm.resetSettings();
	wm.setConnectTimeout(30);
	Serial.print("*wm:Password is ");
	Serial.println(DEFAULT_PASS);
	if (wm.autoConnect(DEFAULT_SSID, DEFAULT_PASS)) {
		Serial.println("*wm:Connected");
		Serial.print("*wm:Visit http://");
		Serial.print(WiFi.localIP());
		Serial.println("/");
		digitalWrite(LED, HIGH);
	} else {
		Serial.println("WiFi connect failed.");
		Serial.println("Perparing AP backup connection.");
		WiFi.mode(WIFI_AP);
		WiFi.softAP(DEFAULT_SSID, DEFAULT_PASS);
		Serial.print("Visit http://");
		Serial.print(WiFi.softAPIP());
		Serial.println("/");
		digitalWrite(LED, HIGH);
	}
	server.onNotFound([]() {
		server.send(200, "text/plain", "404 Not Found");
	});
	server.on("/", HTTP_GET, []() {
		server.send(200, "text/html", HTML_DEFAULT);
	});
	server.on("/hid", HTTP_POST, []() {
		String data = "";
		if (server.hasArg("data")) {
			data = server.arg("data");
			runScript(data);
		}
		server.send(200, "text/plain", data);
	});
	MDNS.begin(DEFAULT_HOST);
	server.begin();
	USB.begin();
	Keyboard.begin();
	Mouse.begin();
	ConsumerControl.begin();
}
void loop() {
	server.handleClient();
}

測試的程式碼

測試效果

總結

由於 ESP32-S2 直接使用 USB Type-A 插頭,而且支援 WiFi 及 USB HID 功能,因此在下覺得更方便連接到電腦
在下亦將之前的 Sketch 修改,只是美中不足的是必須使用 序列輸出 來查看 IP

當連接到 ESP32* 的 WiFi 存取點 (Access Point)
在沒有修改 ESP32* 的 網絡設定的情況下, 預設閘道 (Default Gateway) 的 IP 必定是 192.168.4.1
但如果讓 ESP32-S2-WROOM 連接到其他 WiFi網絡 後,便需要在 序列輸出 才能查看 IP

然而,被連接的 宿主系統 未必有查看 ESP32-S2-WROOM 序列輸出 的軟件,連接的 WiFi網絡 亦未必有存取權查看 已連接網絡的裝置的 IP
因此可以使用 ESPmDNS.h 來設定 ESP32* 的 主機名稱 (Hostname) ,便可以直接以 主機名稱 來連接到 ESP32-S2-WROOM 而不需要獲知 IP

基本上這個專案只是使用 ESP32-S2-WROOM 來代替 ESP32-S3 0.42in OLED 的更新版
效果其實是完全相同,只是加強了方便使用的網頁操作界面

參考資料

沒有留言 :

張貼留言