IBM Watson IoT - 无法使用 ESP8266 从带有参数的主题获得响应

IBM Watson IoT - Unable to get response from topic with parameters using ESP8266

几天来我一直在寻找这个问题:

我想使用 Watson IoT Platform 和 ESP32(或类似产品)制作联网设备 (IoT)。此设备上有一些继电器。

在 Watson 仪表板上,我创建了设备类型,physical/logical 接口,我将 ESP 与平台连接。

我在仪表板上创建了一个自定义操作,它有一个参数来标识我想要切换的继电器 (switch2),还有一个没有参数的简单自定义操作 (switch)。

问题是,如果我生成没有参数 (switch) 的动作,我会看到回调打印,如果我生成带有参数 (switch2) 的动作,则什么也没有发生。 我还尝试使用内置的 Watson 操作 "firmware update/download",如果我使用固件下载(需要一些参数,例如 uri、版本等),如果我使用固件更新(不需要params), 看到订阅的回调了

在这里你可以看到类似ESP的arduino代码

// --------------- HEADERS -------------------
#include <Arduino_JSON.h>

#include <EEPROM.h>

#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>

#include <PubSubClient.h> //https://github.com/knolleary/pubsubclient/releases/tag/v2.3

WebServer server(80);

char wifi_ssid[100] = "xxxxxx";
char wifi_psw[200] = "xxxxxxx";

// ----- Watson IBM parameters
#define ORG "xxxx"
#define DEVICE_TYPE "Relay"
#define DEVICE_ID "xxxx"
#define TOKEN "xxxxxxxxxxxxxxxx"

char ibmServer[] = ORG ".messaging.internetofthings.ibmcloud.com";
char authMethod[] = "use-token-auth";
char token[] = TOKEN;
char clientId[] = "d:" ORG ":" DEVICE_TYPE ":" DEVICE_ID;

const char switchTopic[] = "iotdm-1/mgmt/custom/switch-actions-v1/switch2";
const char testTopic[] = "iotdm-1/mgmt/custom/switch-actions-v1/switch"; //"iot-2/cmd/+/fmt/+";
const char observeTopic[] = "iotdm-1/observe";
const char publishTopic[] = "iot-2/evt/status/fmt/json";
const char responseTopic[] = "iotdm-1/response";
const char deviceResponseTopic[] = "iotdevice-1/response";
const char manageTopic[] = "iotdevice-1/mgmt/manage";
const char updateTopic[] = "iotdm-1/mgmt/initiate/firmware/update";

void callback(char* topic, byte* payload, unsigned int payloadLength);

WiFiClient wifiClient;
PubSubClient client(ibmServer, 1883, callback, wifiClient);

bool outputEnable = false;
bool oldOutputEnable = false;

void setup() {
  // put your setup code here, to run once:
  //Init la porta seriale ed aspetta che si avii
  Serial.begin(115200);
  while(!Serial) {
    delay(1); 
  }

  setupWiFi();
}

void loop() {
  // put your main code here, to run repeatedly:
  if (!client.loop()) {
    mqttConnect();
    initManagedDevice();
  }

  delay(100);
}

// WiFi Settings

void setupWiFi() {
  bool state = false;
  Serial.println("---- Setup WiFi ----");
  Serial.println(wifi_ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_psw);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  mqttConnect();
  initManagedDevice();
  publishStatus();

  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(wifi_ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

// IBM IoT
void mqttConnect() {
 if (!!!client.connected()) {
   Serial.print("Reconnecting MQTT client to "); Serial.println(ibmServer);
   while (!!!client.connect(clientId, authMethod, token)) {
     Serial.print(".");
     delay(500);
   }
   Serial.println();
 }
}

void initManagedDevice() {
 if (client.subscribe("iotdm-1/response")) {
   Serial.println("subscribe to responses OK");
 } else {
   Serial.println("subscribe to responses FAILED");
 }

 if (client.subscribe("iotdm-1/device/update")) {
   Serial.println("subscribe to update OK");
 } else {
   Serial.println("subscribe to update FAILED");
 }

 if (client.subscribe(observeTopic)) {
   Serial.println("subscribe to observe OK");
 } else {
   Serial.println("subscribe to observe FAILED");
 }

 if (client.subscribe(switchTopic)) {
   Serial.println("subscribe to switch OK");
 } else {
   Serial.println("subscribe to switch FAILED");
 }

 if (client.subscribe(testTopic)) {
   Serial.println("subscribe to Test OK");
 } else {
   Serial.println("subscribe to Test FAILED");
 }

 JSONVar root;
 JSONVar d;
 JSONVar supports;
 supports["deviceActions"] = true;
 supports["firmwareActions"] = true;
 supports["switch-actions-v1"] = true;
 d["supports"] = supports;
 root["d"] = d;

 char buff[300] = "";
 JSON.stringify(root).toCharArray(buff, 300);

 Serial.println("publishing device metadata:"); Serial.println(buff);
 if (client.publish(manageTopic, buff)) {
   Serial.println("device Publish ok");
 } else {
   Serial.print("device Publish failed:");
 }
}

void callback(char* topic, byte* payload, unsigned int payloadLength) {
 Serial.print("callback invoked for topic: "); Serial.println(topic);

 if (strcmp (responseTopic, topic) == 0) {
   return; // just print of response for now
 }

 if (strcmp (updateTopic, topic) == 0) {
   handleUpdate(payload);
 }

 if (strcmp(switchTopic, topic) == 0) {
  handleRemoteSwitch(payload);
 }

 if(strcmp(observeTopic, topic) == 0) {
  handleObserve(payload);
 }
}

void sendSuccessResponse(const char* reqId) {
  JSONVar payload;
  payload["rc"] = 200;
  payload["reqId"] = reqId;

  char buff[300] = "";
  JSON.stringify(payload).toCharArray(buff, 300);

  if (client.publish(deviceResponseTopic, buff)) {
    Serial.println("Success sended");
  } else {
    Serial.print("Success failed:");
  }
}

void publishStatus() {
 String payload = "{\"relayStatus\":";
 payload += outputEnable;
 payload += "}";

 Serial.print("Sending payload: "); Serial.println(payload);

 if (client.publish(publishTopic, (char*) payload.c_str())) {
   Serial.println("Publish OK");
 } else {
   Serial.println("Publish FAILED");
 }
}

void handleUpdate(byte* payload) {
  Serial.println("handle Update");
}

void handleObserve(byte* payload) {
  JSONVar request = JSON.parse((char*)payload);
  JSONVar d = request["d"];
  JSONVar fields = d["fields"];
  const char* field = fields[0]["field"];

  if(strcmp(field, "mgmt.firmware") == 0) {
    Serial.println("Upadete the firmware");
    sendSuccessResponse(request["reqId"]);

  } else {
    Serial.println("Unmanaged observe");
    Serial.println(request);
  }
}

void handleRemoteSwitch(byte* payload) {
  Serial.println("handle remote switching");
  //invertedSwitch = !invertedSwitch;
  outputEnable = !outputEnable;

  JSONVar request = JSON.parse((char*)payload);
  const char* id = request["reqId"];
  sendSuccessResponse(id);
}

感谢所有想帮助我的人。

几天后我解决了这个问题,我post在这里回复有同样问题的人:

问题是 PubSubClient 库,它只接受 128 字节的响应消息(包括 header)。 Watson IBM 产生比 128 字节更长的响应消息。

要更改响应消息的缓冲区大小,您需要修改 PubSubClient.h 文件第

#define MQTT_MAX_PACKET_SIZE 128

然后将 128 字节换成更大的数字(例如 1024)。