[英]Problem with RPC calls from Thingsboard to Arduino (ESP32)
我创建了一个简单的Arduino程序,该程序从物联网仪表板上的KnobControl Widget接收位置值并更新伺服位置。 该方案是基于ESP32微微套件GPIO控制和DHT22传感器监控从ThingsBoard网站例子, 主要是工作。
到目前为止,我的代码能够连接到仪表板并从服务器接收“ setPos”和“ 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函数。 您认为问题出在哪里?
好的,我在ThingsBoard包装器库中四处摸索,以尝试并更好地了解处理从服务器传入的RPC文本字符串的代码所发生的情况。 在sendDataArray函数内部,我在for循环内发现了这段奇怪的代码,用于扫描回调数组并将其与传入的RPC字符串进行匹配:
// Do not inform client, if parameter field is missing for some reason
if (!data.containsKey("params")) {
continue;
}
如果调用了不包含params字段的RPC方法,则该方法调用将被完全忽略。 不幸的是,getPos RPC调用就是这种情况。 因此,要解决该问题,我只需注释掉上面的代码即可,现在一切正常。
@thingsboard团队,此代码的原始原理是什么? 应该如何将getValue RPC调用传达给客户端以进行处理?
我试图在另一篇文章中解决此问题,但没有意识到您已经发布了此问题。 该答复没有帮助。 我的查询链接如下。
https://github.com/thingsboard/ThingsBoard-Arduino-MQTT-SDK/issues/10#issuecomment-474368259
我还注意到,当旋钮控件没有发出params键时,thingsboard.h包装程序实际上会使草图短路。 由于旋钮控件在执行getPos方法时不会发出任何“参数”键,因此您的草图代码将永远没有机会以最新值进行响应。
我玩过New debug terminal窗口小部件,并且能够通过发出带有params值的getPos方法来测试旋钮控制窗口小部件RPC调用。 如果在“新建”调试终端提示符下仅输入“ getPos”,则在调试终端中将得到一个空括号作为响应,而在串行输出中将得到{“ method”:“ getPos”}。 就像素描一样。
如果在提示符下输入“ getPos 1”,则应在终端窗口中获取SetPosition值作为响应,并在串行输出中获取“ {{method”:“ getValue”,“ params”:1}”。 值1无关紧要,是否有某种类型的参数可以触发包装程序。
请注意,如果在调试窗口中输入“ setPost 12”,则会将SetPosition变量值更新为12。
我的结论是旋钮控制小部件已损坏。 如果要与包装器一起使用,则需要发出“ params”密钥对。
另一个问题,当让getPos在调试终端中工作时,旋钮控件中显示的数值不会更新。 不知道这是否是最好的测试。 用仪表板刷新浏览器窗口会产生相似的结果。 我认为getMethod应该这样做。
物联网团队:这是怎么回事,可以改进吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.