nodemcu 连接 nodejs scoket 服务

190 阅读3分钟

1 前言

本文实现使用 nodejs、express、scoket.io、nodemcu 以实现在网页、nodemcu、服务器之间实时通信。 使用 Arduino IDE 进行编码。

综上述所,我们需要写一个 scoket 服务的代码,一个 nodemuc 板子的代码,一个网页客户端的代码。

nodemcu 使用 Arduino IDE 编写,所以这里使用的是 C 的语法。

服务端使用 nodejs 编写。

客户端(网页)使用 js 编写。

2、效果展示

1、网页发送信息到服务器->服务器立马将信息发送到 nodemcu

2、nodemcu 也会在一些时候向服务器发送信息

3、文件夹结构

test-nodemcu-scoket          #根文件夹 
    scoketServer             #服务端 
        node_modules
        src
            index.js         服务端代码入口
            
    client                   #服务端 
            index.html       #客户端代码入口
            
    test-nodemcu-scoket.ino  #nodemcu 

4、服务端代码编写

在写别的两个端之前必须要有一个服务,所以先用 express 撸一个服务吧!

下面代码没有任何特殊的,直接使用 express、socket.io 将服务搭起来即可

以下是使用的依赖版本

node@10.16.1

express@4.17.1

socket.io@4.5.4

3002 端口用于服务端。



const bodyParser = require("body-parser");
const express = require("express");
const app = express();
const http = require("http");
const { Server } = require("socket.io");
const server = http.createServer(app);

const port = 3002;

// 解析文件使用。本项目暂时未用到
// for parsing application/json
app.use(bodyParser.json({ limit: "50mb" }));
// for parsing application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));

app.all("*",function (req,res,next) {
    res.set({
        "Content-Type": "text/plain",
        "Access-Control-Allow-Credentials": "true",
        "Access-Control-Allow-Headers": "X-Requested-With,Content-Type,token,authorization",
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Origin": req.headers.origin,
        "Access-Control-Allow-Methods": "POST,GET",
        "Content-Type": "application/json",
    });
    next();
});

app.get(`/hello`,(req,res) => {
    console.log(`收到一个请求:`,req.url)
    res.json({ data: "hello" });
});

const io = new Server(server,{
    allowEIO3: true,
    credentials: true,
    cors: {},
}); 
io.on("connection",(socket) => {
    try {
        console.log("一个新的 scoket 连接");

        io.emit("serverMsg","hi!"); 

        socket.on("clientMsg",function (data) {
            console.log(`收到客户端信息:`,data);
            io.emit("mcuMsg",data);
        });

        socket.on("mcuMsg",function (data) {
            const date = new Date();
            const YY = date.getFullYear();
            const MM = date.getMonth() + 1;
            const DD = date.getDate();
            const H = date.getHours();
            const M = date.getMinutes();
            const S = date.getSeconds();
            // linux 上面有8个时差
            console.log(`[${YY}-${MM}-${DD} ${H + 8}:${M}:${S}] 收到mcu信息:`,data);
        });

        // 发生错误时触发
        socket.on("error",function (err) {
            console.log("socket 错误:",err);
        });
    } catch (err) {
        console.log("socket 错误:",err);
        io.to(socket.id).emit("error",`系统异常:${err}`);
    }
});

server.listen(port,() => {
    console.log(`服务正在运行: http://localhost:${port}`);
});


启动服务后访问康康。

image.png

接着我们写客户端代码来调试ws接口

5、客户端代码编写

发送的数据格式: { data:"xxx" }, 本文中所有的数据交互都用这种格式。

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>

    <body>
        <input type="text" id="text">
        <button id="btn">发送信息</button>
    </body>

</html>
<script type="module">
    import { io } from "https://cdn.socket.io/4.4.1/socket.io.esm.min.js";

    const server = "ws://localhost:3002/"
    // const server = "ws://线上地址,不给你们看.top:3002/"
    const socket = io(server,{
        reconnectionDelayMax: 10000,
        auth: {},
        query: { "my-key": "my-value" }
    });

    socket.on("serverMsg",(data) => {
        console.log("接收到服务端信息:", data);
    });

    const btn = document.querySelector("#btn"),
        input = document.querySelector("#text"); 
    btn.addEventListener("click",function () { 
        // 发送输入框数据
        socket.emit("clientMsg", { data: input.value })
    })
</script>

6、nodemcu 代码编写

这里需要用到一个第三方的库,在 Arduino IDE 中下载不到。自行到 github 下载即可。 arduinoWebSockets:github.com/Links2004/a…

ArduinoJson 这个库直接在 Arduino IDE 安装即可。

/*  
 * 客户端依赖:https://github.com/Links2004/arduinoWebSockets 
*/

#include <ESP8266WiFi.h>  
#include <Arduino.h>
#include <ArduinoJson.h>
#include <WebSocketsClient.h>
#include <SocketIOclient.h>
#include <Hash.h>


#ifndef STASSID
#define STASSID "oldwang"
#define STAPSK "oldwang520"
#endif

const char* ssid = STASSID;
const char* password = STAPSK;

const char* websockets_server_host = "www.不给你们看.top";  // 服务器名
const uint16_t websockets_server_port = 3002;              // 端口
 
SocketIOclient socketIO; 
#define USE_SERIAL Serial

void socketIOEvent(socketIOmessageType_t type, uint8_t* payload, size_t length) {
  switch (type) {
    case sIOtype_DISCONNECT:
      Serial.printf("[IOc] Disconnected!\n");
      break;
    case sIOtype_CONNECT:
      Serial.printf("[IOc] Connected to url: %s\n", payload);

      // join default namespace (no auto join in Socket.IO V3)
      socketIO.send(sIOtype_CONNECT, "/");
      break;
    case sIOtype_EVENT:
      // 获取到服务的消息后打印出来
      Serial.printf("[IOc] get event: %s\n", payload);
      break;
    case sIOtype_ACK:
      Serial.printf("[IOc] get ack: %u\n", length);
      hexdump(payload, length);
      break;
    case sIOtype_ERROR:
      Serial.printf("[IOc] get error: %u\n", length);
      hexdump(payload, length);
      break;
    case sIOtype_BINARY_EVENT:
      Serial.printf("[IOc] get binary: %u\n", length);
      hexdump(payload, length);
      break;
    case sIOtype_BINARY_ACK:
      Serial.printf("[IOc] get binary ack: %u\n", length);
      hexdump(payload, length);
      break;
  }
}

void setup() {
  Serial.begin(115200);
  // Serial.setDebugOutput(true);

  Serial.println();
  Serial.println();
  Serial.print("wifi 连接中 ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  Serial.println("socketIO begin: ");
  // server address, port and URL
  socketIO.begin(websockets_server_host, websockets_server_port, "/socket.io/?EIO=4");

  // event handler
  socketIO.onEvent(socketIOEvent);
}

unsigned long messageTimestamp = 0;
void loop() {
  socketIO.loop();

  uint64_t now = millis();

  // 发送案例:1分钟向服务器发送一次消息
  if (now - messageTimestamp > 60000) {
    messageTimestamp = now;
    sendMsg("mcuMsg", "hi, i'm oldWang."); 
  }
}

// 发送信息的方法
// @msgName 服务端监听的事件名
// @msg     会当到 data 中进行发送
void sendMsg(char msgName[100], char msg[100]) {  
  // 创建一个 scoket.io json 消息
  DynamicJsonDocument doc(1024);
  JsonArray array = doc.to<JsonArray>();

  // 消息名称
  // ps: socket.on('event_name', ....
  array.add(msgName);

  // 添加消息内容
  JsonObject param = array.createNestedObject();
  param["data"] = msg;

  // JSON to String (serializion)
  String output;
  serializeJson(doc, output);

  // Send event
  socketIO.sendEVENT(output);
 
  Serial.print("send:");
  Serial.println(output); 
}

7、链接

1、socket.io/

2、expressjs.com

3、github.com/wangzongmin…

看完点个赞~~~