ESP32-CAM和ESP32本地WebSocket服务器视频传输

介绍

ESP32-CAM 采集图像,并通过wed服务器转发到esp32上播放
效果图:
请添加图片描述服务器转发的数据长度
在这里插入图片描述

实现逻辑

通过node.js搭建wed服务器,esp32-cam通过WebsocketsClient进行图像发送到服务器,服务器再转发到esp32上,并显示到触摸屏上

esp32-cam代码

#include "esp_camera.h"
#include <WiFi.h>
#include <ArduinoWebsockets.h>

#include "camera_pins.h"

const char* ssid = "*********";
const char* password = "*********";

const char* websockets_server_host = "电脑ip地址";
const uint16_t websockets_server_port = 8888;

websockets::WebsocketsClient client;

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

  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 10000000;
  config.pixel_format = PIXFORMAT_JPEG;
  //init with high specs to pre-allocate larger buffers
  if(psramFound()){
    config.frame_size = FRAMESIZE_QVGA; // 320x240
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }


  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }


  WiFi.begin(ssid, password);

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

  Serial.print("Camera Ready! Use ip:");
  Serial.print(WiFi.localIP());
  Serial.println("' to connect");

  while(!client.connect(websockets_server_host,websockets_server_port,"/")){
    delay(500);
    Serial.print(".");
  }

  Serial.println("Socket Connected!");  
}

void loop() {

  if (client.available()) {
    Serial.println("' send to photo");
    // 拍摄图片
    camera_fb_t *fb = esp_camera_fb_get();
    if (!fb) {
      Serial.println("Camera capture failed");
      return;     
    }
    Serial.println(fb->len);
    // 发送图片
    client.sendBinary((const char *)fb->buf, fb->len);
    esp_camera_fb_return(fb);
  }
}

esp32(屏幕配置在TFT_eSPI库的User_Setup.h配置,这里不介绍)

#include <SPI.h>
#include <ArduinoWebsockets.h>
#include <WiFi.h>

#include <TJpg_Decoder.h>
#include <TFT_eSPI.h>

const char* ssid = "**********";
const char* password = "************";

const char* websockets_server_host = "电脑ip"; // 替换为你电脑上WebSocket服务器的本地IP地址
const uint16_t websockets_server_port = 8888; // 替换为你的服务器端口号


using namespace websockets;
WebsocketsClient client;

TFT_eSPI tft = TFT_eSPI();         // Invoke custom library

bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
  if ( y >= tft.height() ) return 0;
  tft.pushImage(x, y, w, h, bitmap);
  return 1;
}


void setup() {
  Serial.begin(115200);
  delay(1000);
  
  tft.begin();
  tft.setRotation(3);
  tft.setTextColor(0xFFFF, 0x0000);
  tft.fillScreen(TFT_BLUE);
  tft.setSwapBytes(true); 

  // The jpeg image can be scaled by a factor of 1, 2, 4, or 8
  TJpgDec.setJpgScale(1);

  // The decoder must be given the exact name of the rendering function above
  TJpgDec.setCallback(tft_output);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  Serial.print("Camera Ready! Use ip:");
  Serial.print(WiFi.localIP());
  Serial.println("' to connect");

  if(client.connect(websockets_server_host, websockets_server_port, "/")) {
    Serial.println("Connected to WebSocket server");
  } else {
    Serial.println("WebSocket connect failed.");
    while(1) {
      delay(1000); // 重连失败则循环等待
    }
  }
}

void loop() {
    if(client.poll()){
      WebsocketsMessage msg = client.readBlocking();
      uint16_t w = 0, h = 0;
      TJpgDec.getJpgSize(&w, &h, (const uint8_t*)msg.c_str(), msg.length());
      Serial.print("Width = "); 
      Serial.print(w); 
      Serial.print(", height = "); 
      Serial.println(h);
 
      //绘制jpg图片
      TJpgDec.drawJpg(0, 0, (const uint8_t*)msg.c_str(), msg.length());
    }  
}

node.js服务器
使用:
安装node.js(https://nodejs.cn/)

mkdir my-websocket-server
cd my-websocket-server
npm init -y
npm install ws

code server.js

node server.js
const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8888 });

wss.on('connection', function connection(ws) {
  console.log('A new client Connected!');
  ws.send('Welcome New Client!');

  ws.on('message', function incoming(data) {
    //console.log('received: %s', data);
    console.log('rec len: %d', data.length);
    wss.clients.forEach(function each(client) {
      if (client !== ws && client.readyState === WebSocket.OPEN) {
        client.send(data);
      }
    });
  });

  ws.on('close', function() {
    console.log('Client has disconnected');
  });
});

console.log('WebSocket server is running on ws://localhost:8888/');
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值