Search code examples
ibm-watsonesp8266esp32watson-iot

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


From several days I searched for this problem:

I want to do a connected device (IoT) using Watson IoT Platform and ESP32 (or similar). This device have some relays on board.

On Watson dashboard I created the device type, the physical/logical interface, I connected the ESP with the platform.

I created a custom action on the dashboard that has a param to identify the relay that I want to switch (switch2) and also a simple custom action (switch) without param.

The problem is that if I generate the action without the param (switch) I see the callback print, if I generate the action with a param (switch2) nothing happens. I tried also to use the built-in Watson action "firmware update/download", if I use firmware download (that want some params such as uri, version, etc.) nothing happens, if I use firmware update (that don't want params), I see the callback of subscription.

Here you can see the code arduino like for the ESP

// --------------- 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);
}

Thanks to everyone that wants to try to help me.


Solution

  • After several days I solved the issue, I post here de response for someone with the same problem:

    The problem is the PubSubClient library, that accept only 128 bytes response message (including header). The Watson IBM produce longer response message than 128 bytes.

    To change the buffer size for the response message, you need to modify the PubSubClient.h file at line

    #define MQTT_MAX_PACKET_SIZE 128
    

    And change the 128 byte with bigger number (eg. 1024).