如何修复从 ESP32 发送的这种 Firebase 消息格式(Arduino、ESP-IDF - 所有文本,未使用 Firebase 库)

How to fix this Firebase message format sent from ESP32 (Arduino, ESP-IDF - all text, no Firebase library used)

我正在尝试让下面的代码正常工作,一年前我最后一次尝试它时它运行良好。在 运行 之后,我的应用程序中没有收到任何通知。在 ESP32 模块上的 Arduino IDE 中使用。除了更新令牌之外,没有对曾经有效的草图进行任何更改。我没有在串行输出中收到 "firebase error" 消息,因此假设没有错误。

WiFiClient client;
String serve = "MY SERVER KEY";
String appToken = "MY APP TOKEN";
String data = "{";
data = data + "\"to\": \"" + appToken + "\",";
data = data + "\"notification\": {";
data = data + "\"body\": \"example body\",";
data = data + "\"title\" : \"my title\" ";
data = data + "} }";

Serial.println("Send data...");
if (client.connect("fcm.googleapis.com", 80)) {
  Serial.println("Connected to the server..");
  client.println("POST /fcm/send HTTP/1.1");
  client.println("Authorization: key=" + serve + "");
  client.println("Content-Type: application/json");
  client.println("Host: fcm.googleapis.com");
  client.print("Content-Length: ");
  client.println(data.length());
  client.print("\n");
  client.print(data);
  Serial.println("data");
  Serial.println(data);

}
else {
  Serial.println("firebase error");
}
Serial.println("Data sent...Reading response..");
while (client.available()) {
  char c = client.read();
  Serial.print(c);
}
Serial.println("Finished!");
client.flush();
client.stop();
}

我刚刚在我的应用程序中更新了 Firebase 并迁移到 AndroidX,并且可以接收从 Firebase 控制台发送的消息,我目前正在使用 this library 成功地在我的应用程序中发送和接收通知。下面是我正在使用的示例,它运行良好。

#include <WiFi.h>
#include <FirebaseESP32.h>

#define WIFI_SSID "YOUR_WIFI_AP"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
#define FIREBASE_HOST "YOUR_FIREBASE_PROJECT.firebaseio.com" //Do not include https:// in FIREBASE_HOST
#define FIREBASE_AUTH "YOUR_FIREBASE_DATABASE_SECRET"

#define FIREBASE_FCM_SERVER_KEY "YOUR_FIREBASE_PROJECT_CLOUD_MESSAGING_SERVER_KEY"
#define FIREBASE_FCM_DEVICE_TOKEN_1 "RECIPIENT_DEVICE_TOKEN"
#define FIREBASE_FCM_DEVICE_TOKEN_2 "ANOTHER_RECIPIENT_DEVICE_TOKEN"

FirebaseData firebaseData1;

unsigned long lastTime = 0;

int count = 0;

void sendMessage();

void setup()
{

    Serial.begin(115200);

    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    Serial.print("Connecting to Wi-Fi");
    while (WiFi.status() != WL_CONNECTED)
    {
        Serial.print(".");
        delay(300);
    }
    Serial.println();
    Serial.print("Connected with IP: ");
    Serial.println(WiFi.localIP());
    Serial.println();

    Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
    Firebase.reconnectWiFi(true);

    firebaseData1.fcm.begin(FIREBASE_FCM_SERVER_KEY);

    firebaseData1.fcm.addDeviceToken(FIREBASE_FCM_DEVICE_TOKEN_1);

    firebaseData1.fcm.addDeviceToken(FIREBASE_FCM_DEVICE_TOKEN_2);

    firebaseData1.fcm.setPriority("high");

    firebaseData1.fcm.setTimeToLive(1000);

    sendMessage();
}

void loop()
{

    if (millis() - lastTime > 60 * 1000)
    {
        lastTime = millis();

        sendMessage();
    }
}

void sendMessage()
{

    Serial.println("------------------------------------");
    Serial.println("Send Firebase Cloud Messaging...");

    firebaseData1.fcm.setNotifyMessage("Notification", "Hello World! " + String(count));

    firebaseData1.fcm.setDataMessage("{\"myData\":" + String(count) + "}");

    //if (Firebase.broadcastMessage(firebaseData1))
    //if (Firebase.sendTopic(firebaseData1))
    if (Firebase.sendMessage(firebaseData1, 0))//send message to recipient index 0
    {

        Serial.println("PASSED");
        Serial.println(firebaseData1.fcm.getSendResult());
        Serial.println("------------------------------------");
        Serial.println();
    }
    else
    {
        Serial.println("FAILED");
        Serial.println("REASON: " + firebaseData1.errorReason());
        Serial.println("------------------------------------");
        Serial.println();
    }

    count++;
}

我试过在前台和后台的应用程序中以数据和通知消息格式发送顶部的代码,但无法收到消息。我想知道 Firebase 格式或规则等内容是否在去年发生了变化。我需要使用顶部的代码而不是库,因为我可以在消息正文中再添加几个键值对,然后发送到 iOS,我过去使用相同的代码成功地完成了这一点。我确信密钥对可以添加到我现在正在处理的库中,但我真的更喜欢顶部代码的简单性。非常感谢任何建议。

我不确定,但我相信问题可能是 Arduino 代码是通过 HTTP 而不是 HTTPS 发送的,我在 FB 文档中读到 HTTPS 是必需的。也许他们改变了它,因为同样的代码在一年前对我来说工作得很好。但是我正在将我的代码迁移到 ESP-IDF 的过程中,下面的这个函数正在处理这个问题,它有轻微的 mods 以符合我在 PlatformIO / VS Code IDE 中使用的 C++。这是唯一改变的地方:

esp_http_client_config_t config = {};
config.url = "https://fcm.googleapis.com/fcm/send";
config.event_handler = _http_event_handler;

我不需要任何类型的 SSL 证书,我只是发送了如图所示的代码。我没有尝试过多地使用 HTTPS 的 Arduino 代码。

static void firebasePost() {
    esp_http_client_config_t config = {}; // important to initialize with "{}" when using C++ on ESP-IDF http client or it will crash easily
    config.url = "https://fcm.googleapis.com/fcm/send";
    config.event_handler = _http_event_handler;
    esp_http_client_handle_t client = esp_http_client_init(&config);
    esp_err_t err = esp_http_client_perform(client);
    const char *post_data = "{\"to\": \"eCiC-20m8Zw:APA91bE4i1rkC(SHORTENED)9JZpbW3gFe5Qfz9BhOFmqua3aeZoDZEQ\",\"notification\": {\"body\": \"Sample Body\",\"title\" : \"Sample Title\"} }";
    esp_http_client_set_header(client, "Authorization", "key=AAAAZrM4XXXX:APA91bFnSr_U15y6mX(SHORTENED)WqaWECxYWaCf_rVPE");
    esp_http_client_set_header(client, "Content-Type", "application/json");
    esp_http_client_set_method(client, HTTP_METHOD_POST);
    esp_http_client_set_post_field(client, post_data, strlen(post_data));
    err = esp_http_client_perform(client);
    if (err == ESP_OK) {
        ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %d",
                 esp_http_client_get_status_code(client),
                 esp_http_client_get_content_length(client));
    } else {
        ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
    }
    esp_http_client_cleanup(client);
} 

Arduino Firebase 库通过 SSL 端口 443(HTTPS 方法)为 FCM 和 RTDB 连接到 Firebase。

您的上述假设不正确。

您的设备令牌无效或不存在。

您不必了解 Arduino 库中的代码。 Google 只接受其服务的安全连接。问题可能是设备 uid 或 FCM 有效负载数据冗余。你用你自己的假设接受你的答案。没有针对此问题的解决方案。您需要在 GitHub 仓库中打开问题。