首页 > 解决方案 > 正确创建/解析 JSON

问题描述

我有一个能够读取温度和湿度的 ESP8266。我们的想法是将这些读数上传到 Firebase 数据库,一旦上传这些数据,就使用 Firebase 的函数触发器采取一些行动。

我有一个从 ESP8622 上传数据的 Arduino 代码。上传的数据是时间戳、传感器 ID、温度和湿度。如下:

void updateDatabase(String &temp, String &humidity, String &temp_feeling)
{

     String path = "/Measurements";
     String SensorID = "1";
     timeClient.update();
    // timeClient.setTimeOffset(3600);

    long timeStamp = timeClient.getEpochTime();
    json.clear().set("id",DEVICE_ID);
    json.set("timestamp",(String)timeStamp);
    json.set("temperature",temp_feeling);
    json.set("humidity",humidity);

    mostrarJSON(json);

    if (Firebase.pushJSON(firebaseData, path,json))
    {
      Serial.println("PASSED");
      Serial.println("PATH: " + firebaseData.dataPath());
      Serial.println("TYPE: " + firebaseData.dataType());
      Serial.println("ETag: " + firebaseData.ETag());
      Serial.print("VALUE: ");
      printResult(firebaseData);
      Serial.println("------------------------------------");
      Serial.println();
    }
    else
    {
      Serial.println("FAILED");
      Serial.println("REASON: " + firebaseData.errorReason());
      Serial.println("------------------------------------");
      Serial.println();
    }

}

此 JSON 上传到 Firebase 数据库。上传数据的结果如下:

Firebase 函数具有此代码来处理上传的最新测量值。

exports.onDataAdded = functions.database.ref('/Measurements').onWrite((change,context)=>{

    const snapshot = change.after;
    const val = snapshot.child("").val()
    console.log(val)
    const temperature = snapshot.child("").child("temperature").val()
    const humidity = snapshot.child("").child("humidity").val()

    console.log(`New data received : temp : ${temperature}, humidity : ${humidity}`)

    takeActionSensorUpdate(temperature,humidity)
    return null
})

Firebase 控制台上的代码结果如下:

在此处输入图像描述 控制台输出是:

在此处输入图像描述 我有一些疑问:

非常感谢你!

标签: node.jsfirebasefirebase-realtime-databasearduinogoogle-cloud-functions

解决方案


我不了解 Arduino,但我认为以下内容将回答您的问题。

我是否在 Arduino 代码上正确构建了 JSON 对象?我应该创建自己的节点名称,而不是为每个测量使用随机的唯一 ID?如果是这样,我该怎么做?

正如我所说,我无法从 Arduino Library 的角度回答(我猜你使用这个),但是让数据库使用唯一键(即你的问题中的“节点名称”)生成一个新的子位置是非常标准的,因为在文档中解释(例如 JavaScript SDK),它是“将数据添加到项目集合的最常见模式”。

如果我仅在收到来自 ESP8266 的新上传时触发代码,为什么要打印多个数据库实例?

这是因为您在Measurements节点级别触发了 Cloud Function。请参阅下文如何为Measurements.

正如您在控制台上看到的那样,温度和湿度数据中的输出显示为空。我想这是因为我在 /Measurements 下添加的每个新测量都有一个自动随机 ID,因为它可以在上传到数据库的对象上看到。如何更改 Firebase 函数的代码以获得我想要的值,在这种情况下,温度和湿度?

同上:change.after表示Measurements节点的数据(触发事件后)。它不代表其中一个孩子的数据。此外,通过这样做snapshot.child(""),您将获得一个undefined值,因为您将一个空字符串传递给child(). 这是一个可以解决问题的 Cloud Function 代码:

exports.onDataAdded = functions.database.ref('/Measurements/{pushId}').onWrite((change,context)=>{

    const afterData = change.after.val();
    console.log(afterData)
    const temperature = afterData.temperature;
    const humidity = afterData.humidity;

    console.log(`New data received : temp : ${temperature}, humidity : ${humidity}`)

    takeActionSensorUpdate(temperature,humidity)  //Double check if this is not asynchronous. If yes you need to wait the asynchronous action is done before returning
    return null
})

正如您将在文档中看到的那样,我们使用通配符(用大括号括起来)指定路径组件。换句话说ref('/Measurements/{pushId}'),匹配/Measurements.


推荐阅读