ESP32CAM MQTT直播

ESP32CAM預設是透過WIFI傳遞mjpeg影像,同網域監看視訊影像很簡單
但是如果跨網域就要利用NAT的IP轉送,設定有點麻煩。

我的ESP32實做書籍:我出書了 ESP32 物聯網專題
博客來網址:https://www.books.com.tw/products/0010901195


實做說明

ESP32CAM預設是透過WIFI傳遞mjpeg影像,同網域監看視訊影像很簡單,但是如果跨網域就要利用NAT的IP轉送,設定有點麻煩。

其他的方式,例如將照片上傳到Google空間,或者把照片上傳到Line等。不過都較為複雜

這次則是使用現在最流行的MQTT轉送照片,並用手機觀看,設定VGA品質每5秒一張,測試幾個小時都很正常。

本次感謝網友楊老師,主內容是他的程式,他還有寫一個車牌辨識,改天請他分享

不過要記得的是我這次用的MQTT沒有安全性,只要有人訂閱同一個Topic就可以觀看你的照片喔

一、材料準備

1.手機,安裝好MQTT APP:MQTT Dash(https://play.google.com/store/apps/details?id=net.routix.mqttdash&hl=zh_TW

2.ESP32CAM

二、ESP32CAM燒錄以下程式

要先安裝程式庫,請利用功能表/草稿碼/匯入程式庫/管理程式庫,輸入關鍵字:PubSubClient,作者為Nick O’Leary這個

安裝PubSubClient程式庫
#include <esp_camera.h>
#include <WiFi.h>
#include <PubSubClient.h>
// ------ 以下修改成你自己的WiFi帳號密碼 ------
const char* ssid = "You";
const char* password = "0933932774";

// ------ 以下修改成你MQTT設定 ------
const char* mqtt_server = "mqtt.eclipseprojects.io";//免註冊MQTT伺服器
const unsigned int mqtt_port = 1883;
#define MQTT_USER               "my_name"             //本案例未使用
#define MQTT_PASSWORD           "my_password"         //本案例未使用
#define MQTT_PUBLISH_Monitor    "yourTopic/esp32cam/pic"  // 放置Binary JPG Image的Topoc,記得要改成自己的


 
// ------ OV2640相機設定 ------------
#define CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27
#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22


 
char clientId[50];
void mqtt_callback(char* topic, byte* payload, unsigned int msgLength);
WiFiClient wifiClient;
PubSubClient mqttClient(mqtt_server, mqtt_port, mqtt_callback, wifiClient);

//啟動WIFI連線
void setup_wifi() {
  Serial.printf("\nConnecting to %s", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.print("\nWiFi Connected.  IP Address: ");
  Serial.println(WiFi.localIP());
}


 
//MQTT callback,本案例沒使用
void mqtt_callback(char* topic, byte* payload, unsigned int msgLength) {

}

//重新連線MQTT Server
boolean mqtt_nonblock_reconnect() {
  boolean doConn = false;
  if (! mqttClient.connected()) {
    boolean isConn = mqttClient.connect(clientId);
    //boolean isConn = mqttClient.connect(clientId, MQTT_USER, MQTT_PASSWORD);
    char logConnected[100];
    sprintf(logConnected, "MQTT Client [%s] Connect %s !", clientId, (isConn ? "Successful" : "Failed"));
    Serial.println(logConnected);
  }
  return doConn;
}

//MQTT傳遞照片
void MQTT_picture() {
  //camera_fb_t * fb;    // camera frame buffer.
  camera_fb_t * fb = NULL;
  fb = esp_camera_fb_get();
  if (!fb) {
    delay(100);
    Serial.println("Camera capture failed, Reset");
    ESP.restart();
  }

  char* logIsPublished;

  if (! mqttClient.connected()) {
    // client loses its connection
    Serial.printf("MQTT Client [%s] Connection LOST !\n", clientId);
    mqtt_nonblock_reconnect();
  }

  if (! mqttClient.connected())
    logIsPublished = "  No MQTT Connection, Photo NOT Published !";
  else {
    int imgSize = fb->len;
    int ps = MQTT_MAX_PACKET_SIZE;
    // start to publish the picture
    mqttClient.beginPublish(MQTT_PUBLISH_Monitor, imgSize, false);
    for (int i = 0; i < imgSize; i += ps) {
      int s = (imgSize - i < s) ? (imgSize - i) : ps;
      mqttClient.write((uint8_t *)(fb->buf) + i, s);
    }


 
    boolean isPublished = mqttClient.endPublish();
    if (isPublished)
      logIsPublished = "  Publishing Photo to MQTT Successfully !";
    else
      logIsPublished = "  Publishing Photo to MQTT Failed !";
  }
  Serial.println(logIsPublished);
 esp_camera_fb_return(fb);//清除緩衝區
}


void setup() {
  Serial.begin(115200);
  //相機設定
  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 = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  config.jpeg_quality = 10;  //10-63 lower number means higher quality
  config.fb_count = 2;
  //設定照片品質
  config.frame_size = FRAMESIZE_QVGA ;// FRAMESIZE_ + UXGA|SXGA|XGA|SVGA|VGA|CIF|QVGA|HQVGA|QQVGA
  esp_err_t err = esp_camera_init(&config);
  delay(500);
  //啟動WIFI連線
  setup_wifi();
  sprintf(clientId, "ESP32CAM_%04X", random(0xffff));  // Create a random client ID
  //啟動MQTT連線
  mqtt_nonblock_reconnect();  
}


 

void loop() {
  mqtt_nonblock_reconnect(); 
  MQTT_picture();//用MQTT傳照片
  delay(10000);
}

燒錄完成後,如果設定沒問題,就可以從序列視窗看到傳遞成功的畫面

燒錄成功,序列視窗畫面

接下來就是設定手機的MQTT接收端

三、手機MQTT設定

安裝好APP後,先設定MQTT伺服器

1.點選右上角的 (+) 符號

MQTT APP開啟畫面

2.輸入與ESP32CAM燒錄時相同的MQTT設定

Name:隨便輸入,自己記得即可
Address:輸入與ESP32CAM程式相同的伺服器,本例:mqtt.eclipseprojects.io
Port:1883
其餘保留預設,按右上角的存檔符號

輸入MQTT設定

3.進入剛建立好的MQTT伺服器內(本例為Esp32cam)

點選右上角的(+)服務,加入新的選項

已建立MQTT伺服器畫面

4.選擇類型為Image

選擇Image類型

5.進入選項設定

先將選項改為第三個Image file data received as binary payload contents
Name:ESP32CAM(自己取名即可)
Topic:請輸入你自己的ESP32CAM程式內相同的Topic
完成後點右上的存檔符號

Image選項設定

6.回到Dashboard時,就可以看到照片不斷的傳入喔

設定完成,畫面成功傳輸

7.可以點入,看大圖

點擊放大觀看

測試了一兩天都沒什麼問題,在此分享給大家,MQTT伺服器也沒關閉連線,真是佛心來著。

4 Comments

  1. 梁阿博

    MQTT APP:MQTT Dash
    這個APP似乎沒辦法下載了,請問有其他的替代app嗎?
    謝謝~

  2. 梁阿博

    老師架的MQTT的網站服務很讚,
    但是我現在是想用手機讀取mqtt的影像,
    如果MQTT Dash的手機app已不支援,請問老師現在用哪一套手機app讀取影像呢?

Leave a Comment

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *