Skip to content

Instantly share code, notes, and snippets.

@ShawnHymel
Created March 3, 2019 22:23
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ShawnHymel/3d124f79aee95fb274876f491a91dcf4 to your computer and use it in GitHub Desktop.
Save ShawnHymel/3d124f79aee95fb274876f491a91dcf4 to your computer and use it in GitHub Desktop.
ESP32 WebSocket Host
#include <WiFi.h>
#include <SPIFFS.h>
#include <ESPAsyncWebServer.h>
#include <WebSocketsServer.h>
// Constants
const char *ssid = "ESP32-AP";
const char *password = "LetMeInPlz";
const char *msg_toggle_led = "toggleLED";
const char *msg_get_led = "getLEDState";
const int dns_port = 53;
const int http_port = 80;
const int ws_port = 1337;
const int led_pin = 15;
// Globals
AsyncWebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(1337);
char msg_buf[10];
int led_state = 0;
/***********************************************************
* Functions
*/
// Callback: receiving any WebSocket message
void onWebSocketEvent(uint8_t client_num,
WStype_t type,
uint8_t * payload,
size_t length) {
// Figure out the type of WebSocket event
switch(type) {
// Client has disconnected
case WStype_DISCONNECTED:
Serial.printf("[%u] Disconnected!\n", client_num);
break;
// New client has connected
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(client_num);
Serial.printf("[%u] Connection from ", client_num);
Serial.println(ip.toString());
}
break;
// Handle text messages from client
case WStype_TEXT:
// Print out raw message
Serial.printf("[%u] Received text: %s\n", client_num, payload);
// Toggle LED
if ( strcmp((char *)payload, "toggleLED") == 0 ) {
led_state = led_state ? 0 : 1;
Serial.printf("Toggling LED to %u\n", led_state);
digitalWrite(led_pin, led_state);
// Report the state of the LED
} else if ( strcmp((char *)payload, "getLEDState") == 0 ) {
sprintf(msg_buf, "%d", led_state);
Serial.printf("Sending to [%u]: %s\n", client_num, msg_buf);
webSocket.sendTXT(client_num, msg_buf);
// Message not recognized
} else {
Serial.println("[%u] Message not recognized");
}
break;
// For everything else: do nothing
case WStype_BIN:
case WStype_ERROR:
case WStype_FRAGMENT_TEXT_START:
case WStype_FRAGMENT_BIN_START:
case WStype_FRAGMENT:
case WStype_FRAGMENT_FIN:
default:
break;
}
}
// Callback: send homepage
void onIndexRequest(AsyncWebServerRequest *request) {
IPAddress remote_ip = request->client()->remoteIP();
Serial.println("[" + remote_ip.toString() +
"] HTTP GET request of " + request->url());
request->send(SPIFFS, "/index.html", "text/html");
}
// Callback: send style sheet
void onCSSRequest(AsyncWebServerRequest *request) {
IPAddress remote_ip = request->client()->remoteIP();
Serial.println("[" + remote_ip.toString() +
"] HTTP GET request of " + request->url());
request->send(SPIFFS, "/style.css", "text/css");
}
// Callback: send 404 if requested file does not exist
void onPageNotFound(AsyncWebServerRequest *request) {
IPAddress remote_ip = request->client()->remoteIP();
Serial.println("[" + remote_ip.toString() +
"] HTTP GET request of " + request->url());
request->send(404, "text/plain", "Not found");
}
/***********************************************************
* Main
*/
void setup(){
// Init LED and turn off
pinMode(led_pin, OUTPUT);
digitalWrite(led_pin, LOW);
// Start Serial port
Serial.begin(115200);
// Make sure we can read the file system
if( !SPIFFS.begin()){
Serial.println("Error mounting SPIFFS");
while(1);
}
// Start access point
WiFi.softAP(ssid, password);
// Print our IP address
Serial.println();
Serial.println("AP running");
Serial.print("My IP address: ");
Serial.println(WiFi.softAPIP());
// On HTTP request for root, provide index.html file
server.on("/", HTTP_GET, onIndexRequest);
// On HTTP request for style sheet, provide style.css
server.on("/style.css", HTTP_GET, onCSSRequest);
// Handle requests for pages that do not exist
server.onNotFound(onPageNotFound);
// Start web server
server.begin();
// Start WebSocket server and assign callback
webSocket.begin();
webSocket.onEvent(onWebSocketEvent);
}
void loop() {
// Look for and handle WebSocket data
webSocket.loop();
}
<!DOCTYPE html>
<meta charset="utf-8" />
<title>WebSocket Test</title>
<script language="javascript" type="text/javascript">
var url = "ws://192.168.4.1:1337/";
var output;
var button;
var canvas;
var context;
// This is called when the page finishes loading
function init() {
// Assign page elements to variables
button = document.getElementById("toggleButton");
output = document.getElementById("output");
canvas = document.getElementById("led");
// Draw circle in canvas
context = canvas.getContext("2d");
context.arc(25, 25, 15, 0, Math.PI * 2, false);
context.lineWidth = 3;
context.strokeStyle = "black";
context.stroke();
context.fillStyle = "black";
context.fill();
// Connect to WebSocket server
wsConnect(url);
}
// Call this to connect to the WebSocket server
function wsConnect(url) {
// Connect to WebSocket server
websocket = new WebSocket(url);
// Assign callbacks
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) };
}
// Called when a WebSocket connection is established with the server
function onOpen(evt) {
// Log connection state
console.log("Connected");
// Enable button
button.disabled = false;
// Get the current state of the LED
doSend("getLEDState");
}
// Called when the WebSocket connection is closed
function onClose(evt) {
// Log disconnection state
console.log("Disconnected");
// Disable button
button.disabled = true;
// Try to reconnect after a few seconds
setTimeout(function() { wsConnect(url) }, 2000);
}
// Called when a message is received from the server
function onMessage(evt) {
// Print out our received message
console.log("Received: " + evt.data);
// Update circle graphic with LED state
switch(evt.data) {
case "0":
console.log("LED is off");
context.fillStyle = "black";
context.fill();
break;
case "1":
console.log("LED is on");
context.fillStyle = "red";
context.fill();
break;
default:
break;
}
}
// Called when a WebSocket error occurs
function onError(evt) {
console.log("ERROR: " + evt.data);
}
// Sends a message to the server (and prints it to the console)
function doSend(message) {
console.log("Sending: " + message);
websocket.send(message);
}
// Called whenever the HTML button is pressed
function onPress() {
doSend("toggleLED");
doSend("getLEDState");
}
// Call the init function as soon as the page loads
window.addEventListener("load", init, false);
</script>
<h2>LED Control</h2>
<table>
<tr>
<td><button id="toggleButton" onclick="onPress()" disabled>Toggle LED</button></td>
<td><canvas id="led" width="50" height="50"></canvas></td>
</tr>
</table>
<div id="output"></div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment