Contents


Overview

Skill Level: Any Skill Level

Intermediate

What is a “managed device"?Being a managed device in the IBM Watson IoT Platform adds powerful capabilities to remotely manage the device and do such things as remote updates, reboots, and perform diagnostics. This recipe shows you how to get started with configuring an ESP8266/Arduino as a managed device.First you’ll need an ESP8266There are a […]

Ingredients

An ESP8266

Step-by-step

  1. What is a

    Being a managed device in the IBM Watson IoT Platform adds powerful capabilities to remotely manage the device and do such things as remote updates, reboots, and perform diagnostics. This recipe shows you how to get started with configuring an ESP8266/Arduino as a managed device.

  2. First you'll need an ESP8266

    There are a variety of types to choose from, all of them should work, here i'm using a NodeMCU style board which is easy to prototype with because it has USB support built in for programming and powering the ESP8266.

  3. Next, install the Arduino IDE

    Get the Arduino IDE here. Using a recent version of the IDE 1.6.5 or later makes it easy to add the ESP8266 support to the IDE. With the Arduino IDE installed use the Board Manager function to add support for the ESP8266, see here for how to do that. https://github.com/esp8266/Arduino#installing-with-boards-manager

  4. Add the MQTT PubSubClient library

    The IBM Watson IoT Platform uses the MQTT protocol so next add the MQTT PubSubClient library to the Arduino IDE. This needs to be a recent version of the library to work with the ESP8266, i'm using version 2.3, from here.

    (You can import a library zip to the Arduino IDE from the IDE menu option Sketch -> Include Library -> Add .ZIP Library)

  5. Add the ArduinoJson library

    The IBM Watson IoT Platform uses Json formatted messages so it makes the Arduino code simpler to use a Json parsing library, I've used ArduinoJson, so add that to the Arduino IDE. I've used version 5.0.7 but any recent version of the library should work. Find it here: https://github.com/bblanchon/ArduinoJson/releases/tag/v5.0.7

    (You can import a library zip to the Arduino IDE from the IDE menu option Sketch -> Include Library -> Add .ZIP Library)

  6. Signup to Bluemix and the IBM Watson IoT Platform

    Next you need to signup on the IBM Watson IoT Platform and create an “organization” and a “device”. This is described in detail at the IBM website and involves signing up to Bluemix and the Internet of Things Platform and in the Bluemix Catalog add an Internet of Things Service. This will create your Organization and then in the IoT Dashboard you can add a Device. There are lots of configuration options, nearly all can be left blank, you just need a device type, i used “ESP8266”, and a device ID, i used “Test1”.

    When the device has been created you'll see the Device Credentials page and you need to save those details which are used to customise your Arduino sketch in the next step.

  7. The Arduino Sketch

    Copy the following sketch to the Arduino IDE:

    /**
    IBM IoT Foundation managed Device

    Author: Ant Elder
    License: Apache License v2
    */
    #include <ESP8266WiFi.h>
    #include <PubSubClient.h> // https://github.com/knolleary/pubsubclient/releases/tag/v2.3
    #include <ArduinoJson.h> // https://github.com/bblanchon/ArduinoJson/releases/tag/v5.0.7

    //-------- Customise these values -----------
    const char* ssid = "<yourWiFiSSID>";
    const char* password = "<yourWiFiPassword>";

    #define ORG "<yourOrg>"
    #define DEVICE_TYPE "yourDeviceType"
    #define DEVICE_ID "yourDevice"
    #define TOKEN "yourDeviceToken"
    //-------- Customise the above values --------

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

    const char publishTopic[] = "iot-2/evt/status/fmt/json";
    const char responseTopic[] = "iotdm-1/response";
    const char manageTopic[] = "iotdevice-1/mgmt/manage";
    const char updateTopic[] = "iotdm-1/device/update";
    const char rebootTopic[] = "iotdm-1/mgmt/initiate/device/reboot";

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

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

    int publishInterval = 30000; // 30 seconds
    long lastPublishMillis;

    void setup() {
    Serial.begin(115200); Serial.println();

    wifiConnect();
    mqttConnect();
    initManagedDevice();
    }

    void loop() {
    if (millis() - lastPublishMillis > publishInterval) {
    publishData();
    lastPublishMillis = millis();
    }

    if (!client.loop()) {
    mqttConnect();
    initManagedDevice();
    }
    }

    void wifiConnect() {
    Serial.print("Connecting to "); Serial.print(ssid);
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    }
    Serial.print("nWiFi connected, IP address: "); Serial.println(WiFi.localIP());
    }

    void mqttConnect() {
    if (!!!client.connected()) {
    Serial.print("Reconnecting MQTT client to "); Serial.println(server);
    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(rebootTopic)) {
    Serial.println("subscribe to reboot OK");
    } else {
    Serial.println("subscribe to reboot FAILED");
    }

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

    StaticJsonBuffer<300> jsonBuffer;
    JsonObject& root = jsonBuffer.createObject();
    JsonObject& d = root.createNestedObject("d");
    JsonObject& metadata = d.createNestedObject("metadata");
    metadata["publishInterval"] = publishInterval;
    JsonObject& supports = d.createNestedObject("supports");
    supports["deviceActions"] = true;

    char buff[300];
    root.printTo(buff, sizeof(buff));
    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 publishData() {
    String payload = "{\"d\":{\"counter\":";
    payload += millis() / 1000;
    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 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 (rebootTopic, topic) == 0) {
    Serial.println("Rebooting...");
    ESP.restart();
    }

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

    void handleUpdate(byte* payload) {
    StaticJsonBuffer<300> jsonBuffer;
    JsonObject& root = jsonBuffer.parseObject((char*)payload);
    if (!root.success()) {
    Serial.println("handleUpdate: payload parse FAILED");
    return;
    }
    Serial.println("handleUpdate payload:"); root.prettyPrintTo(Serial); Serial.println();

    JsonObject& d = root["d"];
    JsonArray& fields = d["fields"];
    for (JsonArray::iterator it = fields.begin(); it != fields.end(); ++it) {
    JsonObject& field = *it;
    const char* fieldName = field["field"];
    if (strcmp (fieldName, "metadata") == 0) {
    JsonObject& fieldValue = field["value"];
    if (fieldValue.containsKey("publishInterval")) {
    publishInterval = fieldValue["publishInterval"];
    Serial.print("publishInterval:"); Serial.println(publishInterval);
    }
    }
    }
    }

     

    Customise the lines after “//——– Customise these values ———–” with your WiFi network SSID and password and with the IoT Device Credentials from the previous step.

  8. Upload and run the sketch

    Upload the sketch to you ESP8266 and then open the Serial Monitor and you should see it register as amanaged device and start publishing data every 30 seconds.

     

  9. View the published data on the IBM Watson IoT Platform Dashboard

    You can see the published events and data from your device on the IoT Dashboard by navigating to your devices and clicking on the device:

     

  10. Reconfigure the device from the IBM Watson IoT Platform Dashboard

    You can open the device configuration from the IoT Dashboard by browsing your devices and clicking on the device, or by going to this URL: https://<yourORG>.internetofthings.ibmcloud.com/dashboard/#/devices/browse/drilldown/<yourDeviceType>/<yourDeviceId>

    Scroll down to the Metadata section and you should see the metadata Json sent from the Arduino:

    Type over the publishInterval value to change it to 10000 and click the Confirm Changes button and you should see in the Arduino Serial Monitor the update request and the Arduino start publishing data every 10 seconds:

     

    Back at the IoT and scroll right to the bottom of the device view to the Action section and it should be showing a Reboot button,

    click that Reboot and you will see in the Arduino Serial Monitor the ESP8266 restarting:

     

     

  11. Thats it!

    Hope you found this a useful introduction to using the ESP8266/Arduino as an IBM Watson IoT Platform's managed device.

    You can find more information about the device management API's in the IBM Watson IoT Platform documentation at: https://docs.internetofthings.ibmcloud.com/#/device-management-operations#device-management-operations

37 comments on"Run an ESP8266/Arduino as a IBM Watson IoT Platform managed device"

  1. On your Arduino sketch, I am getting the following error:

    ‘callback’ was not declared in this scope

    It looks like you need to create a callback function along these lines?

    void callback(const char[] topic, byte* payload, unsigned int length)

    • Sorry I see your callback function now. Not sure why this won’t compile.

      I am also getting this error:

      In function ‘void publishData()’:
      IBMIOT_ESP8266:115: error: expected ‘,’ or ‘;’ before ‘d’
      String payload = “{“d”:}”counter”:”;
      ^

  2. I changed the first line of void(publishData) to:

    String payload = “{\”d\”:{\”counter\”:”;

    and got the sketch working.

    • Glad you got it working. I’m sorry, the escaping of the quote charcters in the JSON string seems to keep get lost by the developerWorks code template. I’ll correct it again now.

  3. The sketch is still working however in the Serial window, the status shows as:
    Reconnecting MQTT client to y7ywk6.messaging.internetofthings.ibmcloud.com
    …………….
    and never makes the connection. Any idea why this might be happening? Everything looks good on my end with my Nodemcu and the Arduino sketch.

  4. TIMO_JUHANI_RASTAS February 08, 2016

    wifiConnect is missing WiFi.begin(ssid, password);
    Arduino IDE scope errors can be avoided by reordering the functions in the code

    • Thanks! I’ve updated the sketch with WiFi. begin.
      I’m guessing the scope issue must be the problem with functions needing to be defined before they are referenced in ESP sketches which appeared in 1.6.6 and 1.6.7 releases of the Arduino IDE? Thats one of a number of issues with the 1.6.6 release so a lot of people have stayed with 1.6.5 for now. Its fixed in the trunk code now so the next release should be good – https://github.com/arduino/arduino-builder/issues/68

  5. Recipes@IoTF February 13, 2016

    Nice recipe, do you mind linking this recipe – https://developer.ibm.com/recipes/tutorials/how-to-register-devices-in-ibm-iot-foundation/ that shows how one can setup IoT Foundation service and register devices in it?

  6. Great example.
    Everything on the Serial Monitor shows as being Published, and the Counter data is visible in the IOT Dashboard Events/Sensor data.
    However, the Metadata window in the IOT Dashboard doesn’t show anything.
    Any Ideas what it could be or what area I should double check

  7. EzequielNĂ©voli October 05, 2016

    to compile gives me the following error:
    ———————————————–
    Arduino: 1.6.8 (Windows 7), Board: “Generic ESP8266 Module, 80 MHz, 40MHz, DIO, 115200, 512K (64K SPIFFS), ck, Disabled, None”

    IOT_Bluemix_ESP01_Managed.ino:33: error: ‘callback’ was not declared in this scope

    PubSubClient client(server, 1883, callback, wifiClient);

    ^

    Multiple libraries were found for “PubSubClient.h”
    Used: C:\Users\IBM_ADMIN\Documents\Arduino\libraries\PubSubClient
    Not used: C:\Users\IBM_ADMIN\Documents\Arduino\libraries\ESP8266_Microgear
    exit status 1
    ‘callback’ was not declared in this scope

    This report would have more information with
    “Show verbose output during compilation”
    option enabled in File -> Preferences.
    ———————————————————
    I see there is a function but do not know why not compile.

    • I-Logix_Disciple October 10, 2016

      I saw the same compile error. Add the following forward declaration of the callback function before the call to PubSubClient client(server, 1883, callback, wifiClient):

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

  8. Also, please note: If the MQTT service disconnects and tries re-connecting, he forgot this line of code in the main program loop:
    initManagedDevice();
    Which re-subscribes to the topics

  9. Hi Ant,
    FYI, I noticed that with the used PubSubClient has an odd payload – bug/limitation. Whenever the message – payload becomes too big, it’s not being delivered at the callback. You can reproduce this by creating a bigger-than-usual json metadata configuration with some dummy-data in it. It will not work, once you have passed a limit of 200(?) chars.
    I noticed that when I was trying the firmwareActions; Subscribing failed. The device-update-message wasn’t coming in. etc. etc. All problems where fixed when I replaced the MQTT-library with http://github.com/Imroy/pubsubclient
    Kind regards,
    Henk-Jan

    • Thats interesting. Searching about that I see it says in the knolleary version of PubSubClient that the default maximum message size is 128 bytes. Thats seems pretty small for a JSON metadata message, I guess the small size is to reduce memory usage on small MCUs but for the ESP8266 it would be fine to have it bigger. I’ll update the code with a comment about this.

  10. RetoKeller March 04, 2017

    Dear Ant Elder,
    Would it also be possible running the ESP8266 as “managed gateway” instead of a “managed device”? Or can only JAVA-supported microcontrollers act as “managed gateways”?
    Thank you!

  11. I got the same errors as above. Serial Monitor say Reconnecting.. and never makes the connection.
    On Watson Logs it gives me the “the operation is not authorized” and parameter values are the ones I got when defining the device.
    Any clues on further debugging or configuration?

  12. Gracias por el tutorial, funciono perfecto!!! Saludos desde MĂ©xico!

  13. Zealous Macwan March 04, 2018

    Hi everyone, I have esp8266 01 type (It’s just wifi module not like nodeMCU) and arduino. How to connect esp to arduino with tx rx pin and use this code ? Please Help me. Will this code work for my config ?

  14. Hi, Iam testing the platform. I get the following error…
    with this debug line, I can get the mqtt answer back from the broker
    mqtt_response = client.state ();
    result is 5 means (5: Connection refused – not authorised )
    I triple checked ORG + TOKEN + DEVICE_ID + DEVICE_TYPE , char authMethod[] = “use-token-auth”; everything seems fine , but not able to connect… dont know what else to look at… thanks

  15. Ananya_anu March 27, 2018

    Hi I was wondering whether this code would work with ESP8266 and arduino?Please help me out.

  16. hello, thanks for your tutorial, but i still don’t have the response (only dots on the serial port) from ibm, it seems that’s disconnected , but i don’t know the reason why!! please can anybody help me??

    • I also have the issue :

      Reconnecting MQTT client to y7ywk6.messaging.internetofthings.ibmcloud.com
      …………….

      The same issue also came up on another example program based on this sketch. Please help

      Thanks!

  17. agnimitrashekhar July 09, 2018

    Same problem for me too. I am just getting lots of ………. and it never connects.
    @antelder, can you help ??

    • Hannes Hoettinger August 31, 2018

      Which port are you using? If you would like to use a secure connection on port 8883 you have to define the client as “WiFiClientSecure”.
      Make sure you have the correct option in the IoT Platform set for TLS (TLS Optional). Try to reset the board once with the hardware buttons next to the Micro USB Connector. Hope that helps 🙂

Join The Discussion