js原生 WebSocket API 与 WebSocketsServer.h 的通信(nodemcu-32s 和 javascript 通信)

前言

当需要手机连接开发板(nodemcu)的wifi,并且和它进行数据通信时,就需要用到本文内容。

本文使用 nodemcu 搭建一个 http 服务和一个webSocket服务,前者用于提供web页面,后者用于在页面中和开发板进行实时通信。

nodemcu http和wss服务搭建

下面代码在 Arduino IDE 中编译。

c 复制代码
#include <WiFiClient.h>        // 调用WiFiClient库,用于建立wifi连接
#include <ESP8266WebServer.h>  // 调用WebServer库,用于构建html页面
#include <WebSocketsServer.h>  // 用于构建ws服务
#include <Arduino_JSON.h>

// wifi 账号密码 
String wifi_name = "test";
String wifi_pwd = "12345678";


// 建立WebServer,端口为80
ESP8266WebServer server(80);
// socket 服务
WebSocketsServer webSocket = WebSocketsServer(81);
#define USE_SERIAL Serial

// 处理接到的消息,代码中演示 json 解析方法
void msg_cb(uint8_t* payload) {
  JSONVar infosObj = JSON.parse((char*)payload);  // 将 payload 转换为 char*
  // if (JSON.typeof(infosObj) == "undefined") {
  //   return;
  // }
  //if (infosObj.hasOwnProperty("dj_deg")) { 
  //   dj_deg = (int)infosObj["dj_deg"]; 
  //} 
}

void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) {
  switch (type) {
    case WStype_DISCONNECTED:
      USE_SERIAL.printf("[%u] Disconnected!\n", num);
      break;
    case WStype_CONNECTED:
      {
        IPAddress ip = webSocket.remoteIP(num);
        USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);

        // send message to client
        webSocket.sendTXT(num, "Connected");
      }
      break;
    case WStype_TEXT:
      USE_SERIAL.printf("[%u] get Text: %s\n", num, payload); 
      msg_cb(payload);

      // send message to client
      // webSocket.sendTXT(num, "message here");
      // send data to all connected clients
      // webSocket.broadcastTXT("message here");
      break;
    case WStype_BIN:
      USE_SERIAL.printf("[%u] get binary length: %u\n", num, length);
      hexdump(payload, length);

      // send message to client
      // webSocket.sendBIN(num, payload, length);
      break;
  }
}

// http 服务 "/" 路由处理函数,返回一个 html 文件
// 这页面文件会直接写到代码中,也可以使用 `FS.h` 存入闪存。
void ctrl_page() {
  String content = "<!DOCTYPE html><html lang='en'><head><meta charset='UTF-8'><meta name='viewport'content='width=device-width, initial-scale=1.0'><title>测试</title><style>body{margin:0;padding:0;width:100%;height:100%}</style></head><body><input id='dj_range'type='range'min='0'max='180'step='1'value='90'style='width: 100%;margin: 50px 0px;'></body></html><script>var server='ws://192.168.4.1:81';var socket=new WebSocket(server);socket.onopen=function(event){console.log('WebSocket 连接已建立');document.querySelector('#dj_range').addEventListener('input',function(e){var val=Number(e.target.value);socket.send(JSON.stringify({dj_deg:val}))})};socket.onmessage=function(event){console.log('收到消息:',event.data)};socket.onclose=function(event){console.log('WebSocket 连接已关闭')};socket.onerror=function(error){console.error('WebSocket 发生错误:',error)};</script>";
  server.send(200, "text/html", content);
}

// 对外接口
void initServer() {
  // 手机控制页面
  server.on("/", ctrl_page); 
  server.begin();
}

void setup() {
  Serial.begin(115200);  // 初始化串口,波特率为 115200
  WiFi.mode(WIFI_AP);                // 将WiFi模式设为AP
  WiFi.softAP(wifi_name, wifi_pwd);  // 开启热点
  
 
  IPAddress ip = WiFi.softAPIP();
  String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);
  String httpUrl = "http://" + ipStr;
  Serial.println("AP IP:");
  Serial.println(ipStr);
  
  // http 服务
  initServer();
    
  // ws 服务
  webSocket.begin();
  webSocket.onEvent(webSocketEvent);
}

void loop() {

  // 处理客户端请求
  server.handleClient();

  webSocket.loop();
}

页面代码

页面代码最后写完后压缩后,放到了上面代码中。

需要注意的是这里用不了 socket.io.js 这个很棒的插件。因为这个插件太大了,放板子里太多余,所以需要手写 js 提供的 api, 详细学习见: developer.mozilla.org/en-US/docs/...

html 文件压缩工具:www.jyshare.com/front-end/4...

html 复制代码
<!DOCTYPE html>
<html lang='en'>

<head>
    <meta charset='UTF-8'>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <title>测试</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>

    <input id='dj_range' type='range' min='0' max='180' step='1' value='90' style='width: 100%;margin: 50px 0px;'>
</body>

</html>
<script>
    // 板子的ip
    var server = 'ws://192.168.4.1:81';
    // 创建 WebSocket 连接
    var socket = new WebSocket(server);

    // 当连接建立时
    socket.onopen = function (event) {
        console.log('WebSocket 连接已建立');

        document.querySelector('#dj_range').addEventListener('input', function (e) {
            var val = Number(e.target.value);
            // 发送 Socket.IO 握手消息
            socket.send(JSON.stringify({ dj_deg: val }));
        })

    };

    // 当收到消息时
    socket.onmessage = function (event) {
        console.log('收到消息:', event.data);
    };

    // 当连接关闭时
    socket.onclose = function (event) {
        console.log('WebSocket 连接已关闭');
    };

    // 当发生错误时
    socket.onerror = function (error) {
        console.error('WebSocket 发生错误:', error);
    };
</script> 

效果

拖动页面滚动条,板子会实时收到消息。

相关推荐
Манго нектар25 分钟前
JavaScript for循环语句
开发语言·前端·javascript
Zheng1132 小时前
【可视化大屏】将柱状图引入到html页面中
javascript·ajax·html
john_hjy2 小时前
【无标题】
javascript
软件开发技术深度爱好者2 小时前
用HTML5+CSS+JavaScript庆祝国庆
javascript·css·html5
汪子熙3 小时前
Angular 服务器端应用 ng-state tag 的作用介绍
前端·javascript·angular.js
昨天;明天。今天。9 小时前
案例-表白墙简单实现
前端·javascript·css
安冬的码畜日常9 小时前
【玩转 JS 函数式编程_006】2.2 小试牛刀:用函数式编程(FP)实现事件只触发一次
开发语言·前端·javascript·函数式编程·tdd·fp·jasmine
小御姐@stella9 小时前
Vue 之组件插槽Slot用法(组件间通信一种方式)
前端·javascript·vue.js
GISer_Jing9 小时前
【React】增量传输与渲染
前端·javascript·面试
GISer_Jing9 小时前
WebGL在低配置电脑的应用
javascript