问答

汇集网友智慧,解决技术难题

21ic问答首页 - 求ESP32通过mqtt和android进行图片传输代码

Android 代码 QT 编译 成功 ap

求ESP32通过mqtt和android进行图片传输代码 赏3000家园币

macpherson2024-11-17
求ESP32通过mqtt和android进行图片传输代码提供apk的编译文件。代码运行成功截图。
提供运行机制说明,自己修改的说明。
回答 +关注 1
2596人浏览 4人回答问题 分享 举报
4 个回答
  • // send_img_aliyun.ino

    #include <WiFi.h>
    #include <Wire.h>
    #include <PubSubClient.h>
    #include <ArduinoJson.h>

    // #include "aliyun_mqtt.h"
    #include "aliyunmqtt.h"

    #include "esp_camera.h"

    #include <SPIFFS.h>
    #include "FS.h"                // SD Card ESP32
    #include "SD_MMC.h"            // SD Card ESP32
    #include "soc/soc.h"           // Disable brownour problems
    #include "soc/rtc_cntl_reg.h"  // Disable brownour problems
    #include "driver/rtc_io.h"
    #include <EEPROM.h>

    // 内存存储相关配置
    #define EEPROM_SIZE 1
    int pictureNumber = 0;
    String msg;
    int buttonState = 0;
    int btnHold = 0;


    // #define SENSOR_PIN 10
    //以下信息需要自己修改
    #define WIFI_SSID "TP-LINK_1760"  //替换自己的WIFI
    #define WIFI_PASSWD "987654321"   //替换自己的WIFI密码

    // 阿里云物联网 三元组
    #define PRODUCT_KEY "k0xxxxxIM"                         //替换自己的PRODUCT_KEY
    #define DEVICE_NAME "esp001_001"                       //替换自己的DEVICE_NAME
    #define DEVICE_SECRET "589xxxxxxxxxxxxxxxxxxxe0f"  //替换自己的DEVICE_SECRET \


    //以下不需修改
    #define ALINK_BODY_FORMAT "{\"id\":\"123\",\"version\":\"1.0\",\"method\":\"%s\",\"params\":%s}"
    #define ALINK_TOPIC_PROP_POST "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/event/property/post"
    #define ALINK_TOPIC_PROP_POSTRSP "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/event/property/post_reply"
    #define ALINK_TOPIC_PROP_SET "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/service/property/set"
    #define ALINK_METHOD_PROP_POST "thing.event.property.post"
    #define ALINK_TOPIC_DEV_INFO "/ota/device/inform/" PRODUCT_KEY "/" DEVICE_NAME ""
    #define ALINK_VERSION_FROMA "{\"id\": 123,\"params\": {\"version\": \"%s\"}}"
    unsigned long lastMs = 0;
    // 测试 初始温度
    int i = 15;

    WiFiClient espClient;
    PubSubClient mqttClient(espClient);

    //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

    static camera_config_t camera_config = {
      .pin_pwdn = PWDN_GPIO_NUM,
      .pin_reset = RESET_GPIO_NUM,
      .pin_xclk = XCLK_GPIO_NUM,
      .pin_sscb_sda = SIOD_GPIO_NUM,
      .pin_sscb_scl = SIOC_GPIO_NUM,

      .pin_d7 = Y9_GPIO_NUM,
      .pin_d6 = Y8_GPIO_NUM,
      .pin_d5 = Y7_GPIO_NUM,
      .pin_d4 = Y6_GPIO_NUM,
      .pin_d3 = Y5_GPIO_NUM,
      .pin_d2 = Y4_GPIO_NUM,
      .pin_d1 = Y3_GPIO_NUM,
      .pin_d0 = Y2_GPIO_NUM,
      .pin_vsync = VSYNC_GPIO_NUM,
      .pin_href = HREF_GPIO_NUM,
      .pin_pclk = PCLK_GPIO_NUM,

      .xclk_freq_hz = 20000000,
      .ledc_timer = LEDC_TIMER_0,
      .ledc_channel = LEDC_CHANNEL_0,

      .pixel_format = PIXFORMAT_JPEG,
      // .frame_size = FRAMESIZE_VGA,
      // FRAMESIZE_UXGA (1600 x 1200)
      // FRAMESIZE_QVGA (320 x 240)
      // FRAMESIZE_CIF (352 x 288)
      // FRAMESIZE_VGA (640 x 480)
      // FRAMESIZE_SVGA (800 x 600)
      // FRAMESIZE_XGA (1024 x 768)
      // FRAMESIZE_SXGA (1280 x 1024)
      .frame_size = FRAMESIZE_QVGA,
      .jpeg_quality = 10,
      // 图像质量(jpeg_quality) 可以是 0 到 63 之间的数字。数字越小意味着质量越高
      .fb_count = 1,
    };

    void init_wifi(const char *ssid, const char *password) {
      WiFi.mode(WIFI_STA);
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        Serial.println("WiFi does not connect, try again ...");
        delay(500);
      }

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

    void mqtt_callback(char *topic, byte *payload, unsigned int length) {
      Serial.print("Message arrived [");
      Serial.print(topic);
      Serial.print("] ");
      payload[length] = '\0';
      Serial.println((char *)payload);

      if (strstr(topic, ALINK_TOPIC_PROP_SET)) {
        StaticJsonBuffer<100> jsonBuffer;
        JsonObject &root = jsonBuffer.parseObject(payload);
        if (!root.success()) {
          Serial.println("parseObject() failed");
          return;
        }
      }
    }

    void mqtt_check_connect() {
      while (!mqttClient.connected())  //
      {
        while (connect_aliyun_mqtt(mqttClient, PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET)) {
          Serial.println("MQTT connect succeed!");
          //client.subscribe(ALINK_TOPIC_PROP_POSTRSP);
          mqttClient.subscribe(ALINK_TOPIC_PROP_SET);

          Serial.println("subscribe done");
        }
      }
    }

    void mqtt_interval_post() {
      //  static int i=0;
      char param[512];
      char jsonBuf[1024];
      sprintf(jsonBuf, "{\"id\":\"1189401707\",\"version\":\"1.0.0\",\"method\":\"%s\",\"params\":{\"img\":\"END\"}}");
      Serial.println(jsonBuf);
      mqttClient.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
      Serial.println("发送结束符");
      delay(1000);
    }



    // 摄像头、SD卡与 SPIFFS 初始化
    esp_err_t camera_init() {
      //initialize the camera
      esp_err_t err = esp_camera_init(&camera_config);
      if (err != ESP_OK) {
        Serial.println("Camera Init Failed");
        return err;
      }
      sensor_t *s = esp_camera_sensor_get();
      //initial sensors are flipped vertically and colors are a bit saturated
      if (s->id.PID == OV2640_PID) {
        //        s->set_vflip(s, 1);//flip it back
        //        s->set_brightness(s, 1);//up the blightness just a bit
        //        s->set_contrast(s, 1);
      }
      Serial.println("Camera Init OK!");
      return ESP_OK;
    }


    void sd_init(void) {
      //SD card init
      if (!SD_MMC.begin()) {
        Serial.println("Card Mount Failed");
        return;
      }
      uint8_t cardType = SD_MMC.cardType();
      if (cardType == CARD_NONE) {
        Serial.println("No SD_MMC card attached");
        return;
      }
    }

    void SPIFFS_init() {
      //初始化SPIFFS
      if (!SPIFFS.begin(true)) {
        Serial.println("An Error has occurred while mounting SPIFFS");
      } else {
        delay(500);
        Serial.println("SPIFFS mounted successfully");
      }
      //Turn-off the 'brownout detector'
      WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
    }
    // 摄像头、SD卡与 SPIFFS 初始化 end



    void setup() {
      Serial.begin(115200);
      Serial.println("程序 Start");
      init_wifi(WIFI_SSID, WIFI_PASSWD);

      camera_init();
      sd_init();
      SPIFFS_init();

      mqttClient.setCallback(mqtt_callback);
    }

    // the loop function runs over and over again forever
    void loop() {

      // 程序开始拍照并保存
      Serial.print("进行拍照\n");
      camera_fb_t *fb = esp_camera_fb_get();
      if (!fb) {
        Serial.print("Camera capture failed");
        return;
      } else {
        EEPROM.begin(EEPROM_SIZE);
        pictureNumber = EEPROM.read(0) + 1;
        // Path where new picture will be saved in SD Card
        String path = "/picture" + String(pictureNumber) + ".jpg";

        fs::FS &fs = SD_MMC;
        Serial.printf("文件名字: %s\n", path.c_str());
        File file = fs.open(path.c_str(), FILE_WRITE);
        if (!file) {
          Serial.println("Failed to open file in writing mode");
        } else {
          file.write(fb->buf, fb->len);  // payload (image), payload length
          Serial.println(fb->len);
          Serial.print("抓拍成功并保存\n");
          Serial.printf("保存路径: %s\n\n", path.c_str());
          EEPROM.write(0, pictureNumber);
          EEPROM.commit();
        }


        String a1 = "{\"id\":\"1189401707\",\"version\":\"1.0.0\",\"method\":\"123\",\"params\":{\"img\":\"";
        String a2;
        String a3 = "\"}}";
        char data[4104];
        // 将图片分为不超过 800 通过 MQTT 发送出去
        for (int i = 0; i < fb->len; i++) {
          sprintf(data, "%02X", *(fb->buf + i));
          a2 += data;
          if (a2.length() == 800) {
            String a4 = a1 + a2;
            String a = a4 + a3;
            char jsonBuf[a.length() + 1];
            for (int i = 0; i < a.length(); i++)
              jsonBuf[i] = a[i];
            jsonBuf[a.length()] = '\0';
            Serial.println(jsonBuf);
            mqttClient.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
            a2 = "", a = "", a4 = "";
            // ms
            delay(200);
          }
        }
        if (a2.length() > 0) {
          String a4 = a1 + a2;
          String a = a4 + a3;
          char jsonBuf[a.length() + 1];
          for (int i = 0; i < a.length(); i++)
            jsonBuf[i] = a[i];
          jsonBuf[a.length()] = '\0';
          Serial.println(jsonBuf);
          mqttClient.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
          a2 = "", a = "", a4 = "";
        }
         // 将图片分为不超过 800 通过 MQTT 发送出去  end
        //  
        char endBuf[100];
        sprintf(endBuf, "{\"id\":\"1189401707\",\"version\":\"1.0.0\",\"method\":\"123\",\"params\":{\"img\":\"END\"}}");
        Serial.println(endBuf);
        mqttClient.publish(ALINK_TOPIC_PROP_POST, endBuf);
        Serial.println("发送结束符");

      }
      Serial.println("图片发送完成了......");
      delay(1000);
      // 图片发送结束后发送 END


      if (millis() - lastMs >= 10000) {
        lastMs = millis();
        mqtt_check_connect();
        // Post  interval 间隔
        // mqtt_interval_post();
      }

      mqttClient.loop();

      unsigned int WAIT_MS = 2000;
      delay(WAIT_MS);  // ms
      Serial.println(millis() / WAIT_MS);
    }

  • const container = require('rhea');
    const crypto = require('crypto');
    const fs = require("fs");

    // 请根据实际情况修改下面的参数
    // host,在物联网平台首页,查看开发配置中查看
    var YourHost="iot-06z00xxxxt6xc.amqp.iothub.aliyuncs.com"
    // 客户端ID,可自定义,长度不可超过64个字符
    var YourClientId="esp32_001"
    // 账号的 AccessKey。将鼠标移至账号头像上,然后单击AccessKey管理,获取AccessKey ID和AccessKey Secret。
    var YourAccessKeyId="LTAI5tXXXXXXXXXXxLEMGYL2"
    var YourAccessKeySecret="6vi2Txxxw9xxxrwig"
    // 在对应实例的消息转发 > 服务端订阅 > 消费组列表查看您的消费组ID。
    var YourConsumerGroupId="DEFAULT_GROUP"
    // 物联网平台首页实例 ID
    var YourIotInstanceId="iot-0600uxtxxsx"

    // 存放完整的图片字符串
    var imgStr = ""

    // 16进制图片转base64
    function to_base64(str) {
        var digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        var base64_rep = "";
        var cnt = 0;
        var bit_arr = 0;
        var bit_num = 0;

        for (var n = 0; n < str.length; ++n) {
            if (str[n] >= 'A' && str[n] <= 'Z') {
                ascv = str.charCodeAt(n) - 55;
            }
            else if (str[n] >= 'a' && str[n] <= 'z') {
                ascv = str.charCodeAt(n) - 87;
            }
            else {
                ascv = str.charCodeAt(n) - 48;
            }
            bit_arr = (bit_arr << 4) | ascv;
            bit_num += 4;
            if (bit_num >= 6) {
                bit_num -= 6;
                base64_rep += digits[bit_arr >>> bit_num];
                bit_arr &= ~(-1 << bit_num);
            }
        }
        if (bit_num > 0) {
            bit_arr <<= 6 - bit_num;
            base64_rep += digits[bit_arr];
        }
        var padding = base64_rep.length % 4;
        if (padding > 0) {
            for (var n = 0; n < 4 - padding; ++n) {
                base64_rep += "=";
            }
        }
        return base64_rep;
    }

    //创建Connection。
    var connection = container.connect({
        //接入域名,请参见AMQP客户端接入说明文档。
        'host': YourHost,
        'port': 5671,
        'transport':'tls',
        'reconnect':true,
        'idle_time_out':60000,
        //userName组装方法,请参见AMQP客户端接入说明文档。
        'username':YourClientId+'|authMode=aksign,signMethod=hmacsha1,timestamp=1573489088171,authId='+YourAccessKeyId+',iotInstanceId='+YourIotInstanceId+',consumerGroupId='+YourConsumerGroupId+'|',
        //计算签名,password组装方法,请参见AMQP客户端接入说明文档。
        'password': hmacSha1(YourAccessKeySecret, 'authId='+YourAccessKeyId+'&timestamp=1573489088171'),
    });

    //创建Receiver Link
    var receiver = connection.open_receiver();

    //接收云端推送消息的回调函数。
    container.on('message', function (context) {
        var msg = context.message;
        var messageId = msg.message_id;
        var topic = msg.application_properties.topic;
        var content = Buffer.from(msg.body.content).toString();

        // 输出内容。
        console.log(content);

        // 将接收到的mqtt消息中内容转为json
        var imgBody = JSON.parse(content).items.img.value
        console.log('-------')
        // 如果图片没有传输完毕,则拼接图片
        if (imgBody != 'END') {
            imgStr += imgBody
        } else {
            // 如果图片传输完毕,则将图片转为base64
            console.log('imgStr:')
            console.log(to_base64(imgStr))
            // 配置图片保存路径
            var path = './img/' + new Date().getTime() + '.jpg';
            var dataBuffer = new Buffer(to_base64(imgStr), 'base64'); //把base64码转成buffer对象,
            //用fs将图片写入本地文件
            fs.writeFile(path, dataBuffer, function (err) {
                if (err) {
                    console.log(err);
                } else {
                    console.log('写入成功!');
                }
            });
            // 图片转换完毕后,清空imgStr,准备接受下一张图片
            imgStr = ""

        }
        //发送ACK,注意不要在回调函数有耗时逻辑。
        context.delivery.accept();
    });


    //计算password签名。
    function hmacSha1(key, context) {
        return Buffer.from(crypto.createHmac('sha1', key).update(context).digest())
            .toString('base64');
    }

  • 本帖最后由 3472076282 于 2024-11-26 09:42 编辑

    ESP32 端代码
    首先,确保你已经安装了所需的库,例如 PubSubClient WiFi
    #include <WiFi.h>
    #include <PubSubClient.h>
    // WiFi credentials
    const char* ssid = "your_SSID";
    const char* password = "your_PASSWORD";
    // MQTT Broker
    const char* mqtt_server = "broker.hivemq.com";
    WiFiClient espClient;
    PubSubClient client(espClient);
    void setup() {
      Serial.begin(115200);
      setup_wifi();
      client.setServer(mqtt_server, 1883);
    }
    void setup_wifi() {
      delay(10);
      Serial.println();
      Serial.print("Connecting to ");
      Serial.println(ssid);
      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());
    }
    void reconnect() {
      while (!client.connected()) {
        Serial.print("Attempting MQTT connection...");
        if (client.connect("ESP32Client")) {
          Serial.println("connected");
        } else {
          Serial.print("failed, rc=");
          Serial.print(client.state());
          Serial.println(" try again in 5 seconds");
          delay(5000);
        }
      }
    }
    void loop() {
      if (!client.connected()) {
        reconnect();
      }
      client.loop();
    }
            
       
    Android 端代码
    Android端,你可以使用Paho MQTT库来连接到MQTT Broker并发送/接收消息。以下是一个基本的示例:
    1. 添加依赖项到你的 build.gradle 文件:
            
    dependencies {
        implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
        implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
    }
       
    2. 创建一个服务来处理MQTT连接:
            
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import org.eclipse.paho.android.service.MqttAndroidClient;
    import org.eclipse.paho.client.mqttv3.IMqttActionListener;
    import org.eclipse.paho.client.mqttv3.IMqttToken;
    import org.eclipse.paho.client.mqttv3.MqttCallback;
    import org.eclipse.paho.client.mqttv3.MqttMessage;
    public class MqttService extends Service {
        private static final String MQTT_BROKER_URL = "tcp://broker.hivemq.com:1883";
        private static final String CLIENT_ID = "AndroidClient";
        private MqttAndroidClient mqttAndroidClient;
        @Override
        public void onCreate() {
            super.onCreate();
            mqttAndroidClient = new MqttAndroidClient(this, MQTT_BROKER_URL, CLIENT_ID);
            mqttAndroidClient.setCallback(new MqttCallback() {
                @Override
                public void connectionLost(Throwable cause) {
                    // handle connection loss
                }
                @Override
                public void messageArrived(String topic, MqttMessage message) throws Exception {
                    // handle incoming message
                }
                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {
                    // handle message delivery complete
                }
            });
        }
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            connectToMqttBroker();
            return START_STICKY;
        }
        private void connectToMqttBroker() {
            try {
                mqttAndroidClient.connect(null, new IMqttActionListener() {
                    @Override
                    public void onSuccess(IMqttToken asyncActionToken) {
                        // subscribe to a topic or publish a message
                    }
                    @Override
                    public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                        // handle failure to connect
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
       
    3. 启动服务:
            
    Intent serviceIntent = new Intent(this, MqttService.class);
    startService(serviceIntent);
       
    4. 发布或订阅消息:
            
        // To publish a message
    String topic = "test/topic";
    String message = "Hello from Android";
    try {
        mqttAndroidClient.publish(topic, message.getBytes(), 0, false);
    } catch (Exception e) {
        e.printStackTrace();
    }
      
    // To subscribe to a topic
    String topic = "test/topic";
    try {
        mqttAndroidClient.subscribe(topic, 0);
    } catch (Exception e) {
        e.printStackTrace();
    }
          
    图片传输示例
    假设你要传输一张图片,可以将图片转换为字节数组并通过MQTT发送。以下是一个简单的例子:
    ESP32 端接收图片数据:
    void callback(char* topic, byte* payload, unsigned int length) {
      // Assuming the payload is the image data in bytes
      for (int i = 0; i < length; i++) {
        Serial.print((char)payload);
      }
      Serial.println();
    }
       
    Android 端发送图片数据:
    Bitmap bitmap = ... // your bitmap image
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); // bmp is your Bitmap instance
    byte[] bytes = baos.toByteArray();
    String base64Image = Base64.encodeToString(bytes, Base64.DEFAULT);
    try {
        mqttAndroidClient.publish("image/topic", base64Image.getBytes(), 0, false);
    } catch (Exception e) {
        e.printStackTrace();
    }
       
    以上代码展示了如何在ESP32Android之间通过MQTT进行图片传输的基本方法。根据你的具体需求,你可能需要进一步优化和调整代码。

您需要登录后才可以回复 登录 | 注册