RPC呼叫从Thingsboard到Arduino的问题(ESP32)

Problem with RPC calls from Thingsboard to Arduino (ESP32)

本文关键字:问题 ESP32 Arduino 呼叫 Thingsboard RPC      更新时间:2023-10-16

我创建了一个简单的Arduino程序,该程序从我的Things Boards仪表板上的KnobControl小部件接收位置值并更新伺服位置。该程序基于ESP32 PICO KIT GPIO控制和DHT22传感器监视器示例,来自Thingsboard网站,主要是工作。

到目前为止,我的代码能够连接到仪表板并从服务器接收" setPos"answers" getPos" RPC命令,到目前为止,它可以成功地运行" setPos"呼叫的关联的RPC_Response函数,并且可以移动伺服器。

但是,当我刷新仪表板并将其发送给控制器以获取当前伺服值的" getPos"呼叫时,我在序列输出中收到一个SDK消息,表明控制器接收了命令,但是相关的RPC_Response功能从未调用。我不确定我缺少什么,但是这是我到目前为止写的完整代码示例:

#include <WiFi.h>
#include <ESP32Servo.h>
#include <ThingsBoard.h>
// Constants
#define SERVO_PIN               19      // Servo Output Pin
#define SERVO_UPDATE_INTERVAL   20      // Speed of servo position updates
// Helper macro to calculate array size
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
// WiFi Login Info
#define ssid                "IoT"
#define password            "password"
// MQTT Broker IP address:
#define THINGSBOARD_SERVER  "10.10.0.30"
// MQTT Client Info
#define ACCESS_TOKEN "ESP32_DEMO_TOKEN"
// Servo Variables
int minUs = 500;
int maxUs = 2400;
int SetPosition = 0; // ServoMotor Position Setpoint
int Position = 0;    // ServoMotor current position
// Control/Timing Variables
long lastServoTime = 0;       // keeps track of timestamp since the last servo update occured
// Objects
Servo ServoMotor;
WiFiClient espClient;
ThingsBoard client(espClient);
// RPC Callbacks
RPC_Callback callbacks[] = {
  { "setPos", setPosition },
  { "getPos", getPosition },
};
void setup() {
  Serial.begin(115200);
  // Initialize Servo
  ServoMotor.setPeriodHertz(50);                  // Standard 50hz servo
  ServoMotor.attach(SERVO_PIN, minUs, maxUs);
  // Initialize the WiFi and MQTT connections
  setup_wifi();
}
void loop() {
  // Update/refresh the Wifi/MQTT connection
  updateWirelessConnection();
  // Update Servo Positions
  updateServo();
}
void updateWirelessConnection()
{
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}
// Processes function for RPC call "getPos"
// RPC_Data is a JSON variant, that can be queried using operator[]
// See https://arduinojson.org/v5/api/jsonvariant/subscript/ for more details
RPC_Response getPosition(const RPC_Data &data)
{
  Serial.println("Received the get Position Method");
  return RPC_Response(NULL, SetPosition);
}
// Processes function for RPC call "setPos"
// RPC_Data is a JSON variant, that can be queried using operator[]
// See https://arduinojson.org/v5/api/jsonvariant/subscript/ for more details
RPC_Response setPosition(const RPC_Data &data)
{
  Serial.print("Received the Set Position method: ");
  SetPosition = data;
  Serial.println(SetPosition);
  return RPC_Response(NULL, SetPosition);
}
void updateServo()
{
  long currentTime = millis();
  if (currentTime - lastServoTime > SERVO_UPDATE_INTERVAL) {
    lastServoTime = currentTime;
    // Approach the Horizontal set point incrementally and update the servo if applicable
    if (Position != SetPosition) {
      Position = SetPosition;
      ServoMotor.write(Position);
    }
  }
}
void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  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() {
  // Loop until we're reconnected
  while (!client.connected())
  {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(THINGSBOARD_SERVER, ACCESS_TOKEN)) {
      Serial.println("connected");
      // Perform a subscription. All consequent data processing will happen in
      // callbacks as denoted by callbacks[] array.
      if (!client.RPC_Subscribe(callbacks, COUNT_OF(callbacks))) {
        Serial.println("Failed to subscribe for RPC");
        return;
      }
      Serial.println("Subscribe done");
    } else {
      Serial.println("Failed to connect. Trying again in 5 seconds...");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

另外,当我刷新仪表板时,这是我在串行显示器中看到的响应:

{"method":"getPos"}
[SDK] received RPC getPos
[SDK] response {}

当我更新旋钮控件在仪表板上的位置时,这是我在串行显示器中收到的内容:

{"method":"setPos","params":"135"}
[SDK] received RPC setPos
[SDK] calling RPC setPos
Received the Set Position method: 135
[SDK] response 135

注意:我对SETPOS调用没有任何问题,这会正确调用RPC功能。

作为最后的注意,当我刷新仪表板时,错误消息说:"无法解析响应:[对象对象]"旋钮控制小部件的顶部出现。

因此,主要问题是未调用正确的RPC函数。您认为问题在这里是什么?

好吧,我在Things board包装库中戳了一下,以尝试更好地了解处理服务器传入的RPC文本字符串的代码正在发生的事情。在SenddataArray函数中查看,我在for循环中发现了这件好奇的代码,该代码扫描回调数组,并与Incomming RPC字符串匹配:

// Do not inform client, if parameter field is missing for some reason
if (!data.containsKey("params")) {
    continue;
}

如果调用不包含参数字段的RPC方法,则该方法调用将被完全忽略。不幸的是,GETPOS RPC呼叫就是这种情况。因此,要解决该问题,我简单地评论了上述代码,现在一切都起作用。

@thingsboard团队,此代码的原始原理是什么?GetValue RPC调用应该如何传达给客户的处理?

我试图在另一篇文章中解决该问题,而不是意识到您已经发布了此问题。回应无济于事。我查询的链接在下面。

https://github.com/thingsboard/thingsboard-arduino-mqtt-sdk/issues/10#issuecomment-474368259

我也注意到了东西板。h包装器本质上是简短的电路,当没有从旋钮控件发出参数键时,草图。由于旋钮控件执行getPOS方法时不会发出任何" params"键,因此您的草图代码永远不会有机会使用最新值响应。

我播放了新的调试终端小部件,并能够通过发出带有params值的getPOS方法来测试旋钮控制小部件RPC调用。如果仅在新的调试终端提示中输入" getPos",则在调试终端中获得空括号作为响应,而{" method":" getPos"}在序列输出中。就像草图一样。

如果在提示符下输入'getPos 1',则应在终端窗口中获得setPosition值作为响应,然后在序列输出中将'{" method":" getValue"," params":1}'获取。值1并不重要,有某种参数可以触发包装器。

请注意,如果您在调试窗口中输入'setPost 12',则将将setposition变量值更新为12。

我的结论是旋钮控制小部件被削弱。如果要与包装器一起使用,则需要发布"参数"密钥对。

另一个问题,当您将GETPO在调试终端工作时,旋钮控件中显示的数字值不会更新。不确定这是否是最好的测试。刷新带有仪表板的浏览器窗口会产生相似的结果。我认为GetMethod应该这样做。

事物板团队:这里发生了什么,可以改进?