Demo 33: Monitor and control ESP32 via IBM Bluemix Watson IoT Platform

1. Introduction
2. Hardware
3. Bluemix setup steps and ESP32 software
4. How to monitor and control ESP32
    4.1 Node-Red
    4.2 Using own developed Python application
5. Using graph to display data
6. Using Alert Notification
7. Message Hub

1. Introduction
In this demo, I will show you how to monitor and control ESP32 via IBM Bluemix Watson IoT Platform.
IBM Bluemix is a cloud platform that supports many products and services such as: Compute Infrastructure, Compute Services, Storage, Mobile, Wason, Application services, Data and analytics, Internet of Things, ...
In this demo, we just focus on Internet of Things service of Bluemix.
In order to use Bluemix, you need to register an account. I registered a free account and it is available in 30 trial days.
You can sign up here. It is easy just follow the steps in registration form.
Here is the model of our demo: ESP32 communicate with Node-RED and Python app via IBM Bluemix Watson IoT Platform.

Figure: ESP32 communicate with Node-RED, Python app via Bluemix
2. Hardware
You need a LED or relay as in Demo 1: Blinky
3. Bluemix setup steps and ESP32 software
Here is the Menu of Bluemix services. It is in top-left corner.
But before using IoT service we need to create a Space (where you deploy your IoT application) for it. It is under Manage - Account - Organizations tabs.

From Menu choose IoT service
Choose Create IoT Service and Internet of Thins Platform
Edit fields as your expectation and choose Create ... Done
From Menu choose Dashboard
 Choose IoT service which you created and choose Launch
Now you see IBM Watson IoT Platform dashboard with Menu
Choose Devices and Add Device
Before adding new device, It will recommend you to add Device Type and related device information first.

Here you can fill it with expected information or leave them empty (modify them later).
After creating Device Type, you can add new device.
Here, Device ID is MAC address of ESP32. You can use the code below to get MAC address:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
uint64_t chipid;  

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

void loop() {
 chipid=ESP.getEfuseMac();//The chip ID is essentially its MAC address(length: 6 bytes).
 Serial.printf("ESP32 Chip ID = %04X",(uint16_t)(chipid>>32));//print High 2 bytes
 Serial.printf("%08X\n",(uint32_t)chipid);//print Low 4bytes.

 delay(3000);

}
And let authentication token is Auto-generated. Finally, you have:
Remember to save this information for future use.
Note:  TLS with Token Authentication is enabled by default. So if your device use TLS you can ignore it. In my demo using ESP32, I do not use TLS so I have to disable it to avoid Authentication error. In order to disable it just chose Security from Menu.
Choose Connection Security and then TLS Optional.

Now choose Devices from Menu, you will see a list of devices with Disconnected sign. It is time to connect our devices first time.
In order to connect to IBM Watson™ IoT Platform, we will use MQTT protocol (Demo 14). You can refer document to understand the procedure to connect to it. The Arduino ESP32 code will do the jobs:
- Connect to cloud.
- Publish a temperature message (generated by using random function). If you have DHT11/DHT22 you can use Demo 3.
- Subscribe the ON/OFF message to control LED.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
#include <WiFi.h>
#include <WiFiClient.h>
#include <PubSubClient.h> 

//-------- your wifi -----------
const char* ssid = "dd-wrt";
const char* password = "0000000000";

#define ORG "910d3w"
#define DEVICE_TYPE "ESP32_IoTSharing"
#define DEVICE_ID "A09E02A4AE30"
#define TOKEN "b(N4qP3@Lx!ydaoiEM"
//-------- Bluemix information to build up MQTT message -------

char server[] = ORG ".messaging.internetofthings.ibmcloud.com";
char pubTopic[] = "iot-2/evt/status/fmt/json";
char subTopic[] = "iot-2/cmd/test/fmt/String";
char authMethod[] = "use-token-auth";
char token[] = TOKEN;
char clientId[] = "d:" ORG ":" DEVICE_TYPE ":" DEVICE_ID;

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

const char led = 4;

void receivedCallback(char* pubTopic, byte* payload, unsigned int length) {
  Serial.print("Message received: ");
  Serial.println(pubTopic);

  Serial.print("payload: ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
  /* we got '1' -> on */
  if ((char)payload[0] == '1') {
    digitalWrite(led, HIGH); 
  } else {
    /* we got '0' -> on */
    digitalWrite(led, LOW);
  }
}

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

    if (!client.connected()) {
        Serial.print("Reconnecting client to ");
        Serial.println(server);
        while (!client.connect(clientId, authMethod, token)) {
            Serial.print(".");
            delay(500);
        }
        client.setCallback(receivedCallback);
        if (client.subscribe(subTopic)) {
            Serial.println("subscribe to cmd OK");
        } else {
            Serial.println("subscribe to cmd FAILED");
        }
        Serial.println("Bluemix connected");
    }
}

long lastMsg = 0;
long temperature = 0;

void loop() {
    client.loop();
    long now = millis();
    if (now - lastMsg > 3000) {
        lastMsg = now;
        temperature = random(0, 40);
        String payload = "{\"d\":{\"Name\":\"" DEVICE_ID "\"";
              payload += ",\"temperature\":";
              payload += temperature;
              payload += "}}";
        Serial.print("Sending payload: ");
        Serial.println(payload);

        if (client.publish(pubTopic, (char*) payload.c_str())) {
            Serial.println("Publish ok");
        } else {
            Serial.println("Publish failed");
        }
    }
}
4. How to monitor and control ESP32
We went through steps to setup Bluemix IoT Platform and ESP32. Now we will learn how to develop or setup applications to monitor and control ESP32 Iot device. There are some ways to do that. In this demo, I will use 2 ways: Node-Red (you can refer Demo 8 to know more about Node-RED) and own developed Python application.
4.1 Node-Red
We will use Bluemix Node-RED Starter.
From Menu choose Clound Foundry Apps and then Create Clound Foundry apps. From Filter box search "Node-RED Starter". Choose "Node-RED Starter" and fill expactation information.

Click Create
Waiting until service was deployed ...
 Figure: Node-RED service was deployed successfully
Next, from Menu choose Dashboard and you can see "Node-RED" is running. And you can access Node-RED flow editor online by going to the link in Route column (it is "iotsharing.mybluemix.net")
Now, we need to bind our Node-RED starter with our created Bluemix IoT Platform service. From dashboard and Cloud Foundry Apps table, click the Node-RED row (picture above).
Choose Connect existing and choose the Bluemix IoT Platform service which we created in Section 3 Bluemix setup steps and ESP32 software (the result is similar to picture above).
 Figure: Bind Node-RED with Bluemix IoT Platform
4.1.1 Let 's play with Node-RED
We go to the link in Route column ("iotsharing.mybluemix.net").
And choose Go to your Node-RED flow editor (you may need to wait a little time to initialize Node-RED flow editor if you see 404 error).
Finally, it is done.
Node-RED Starter supports 2 nodes named IBM IoT in/out to connect to Bluemix IoT Platform easily. I created the flow as picture above and Export that flow to JSON format. So you just Import the JSON content into your Flow and change Device Information accordingly to the device which you created in Section 3 Bluemix setup steps and ESP32 software. In my Flow there are 2 blocks: 1 subscribe block (upper block; using IBM IoT in) to subscribe the event from ESP32 IoT device and bring to Debug block through Debug tab (Top-Right corner); 1 publish block (lower block; using IBM IoT out) to publish command ON/OFF LED to ESP32 IoT device.
1
[{"id":"4e411612.28415","type":"ibmiot in","z":"8045a5ff.31e1a","authentication":"boundService","apiKey":"","inputType":"evt","deviceId":"+","applicationId":"","deviceType":"+","eventType":"+","commandType":"","format":"json","name":"IBM IoT","service":"registered","allDevices":true,"allApplications":"","allDeviceTypes":true,"allEvents":true,"allCommands":"","allFormats":true,"qos":0,"x":390,"y":240,"wires":[["ceb56042.2e178"]]},{"id":"ceb56042.2e178","type":"debug","z":"8045a5ff.31e1a","name":"","active":true,"console":"false","complete":"true","x":549.5,"y":243,"wires":[]},{"id":"b9caad0a.f9f158","type":"ibmiot out","z":"8045a5ff.31e1a","authentication":"boundService","apiKey":"","outputType":"cmd","deviceId":"A09E02A4AE30","deviceType":"ESP32_IoTSharing","eventCommandType":"test","format":"String","data":"hello","qos":0,"name":"IBM IoT","service":"registered","x":541.5,"y":320,"wires":[]},{"id":"b1794401.410fb8","type":"inject","z":"8045a5ff.31e1a","name":"","topic":"","payload":"switch","payloadType":"str","repeat":"","crontab":"","once":false,"x":190,"y":320,"wires":[["2c5784ef.d41054"]]},{"id":"2c5784ef.d41054","type":"function","z":"8045a5ff.31e1a","name":"blinky","func":"\nvar flip = context.get('flip')||0;\nif(flip == 1){\n    msg.payload = \"1\";\n    context.set('flip',0);\n}else{\n    msg.payload = \"0\";\n    context.set('flip',1);    \n}\nreturn msg;","outputs":1,"noerr":0,"x":350,"y":320,"wires":[["b9caad0a.f9f158"]]}]
Figure: Import JSON content to Flow
Figure: Change Device Type and Device Id to yours
 4.1.2 Result

Figure: Node-RED receive event from ESP32 IoT in debug tab
4.2 Using own developed Python application
4.2.1 Setup
We will use PAHO MQTT Python (refer Demo 14) for our application.
First, we need to generate API Key for our application.
From IBM Watson IoT Platform dashboard chose APPS:
Then choose Generate API Key
Remember to save this information for future use.
Here is the full Python code using Paho MQTT
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
from random import randint
import thread
import sys
try:
    import paho.mqtt.client as mqtt
except ImportError:
    import os
    import inspect
    cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"../src")))
    if cmd_subfolder not in sys.path:
        sys.path.insert(0, cmd_subfolder)
    import paho.mqtt.client as mqtt

ORG = "910d3w"
DEVICE_TYPE = "ESP32_IoTSharing"
APP_ID = "iotsharingdotcom" #choose any string 
TOKEN = "86a2mx(YZaYo0*&)B6"
DEVICE_ID = "A09E02A4AE30"

server = ORG + ".messaging.internetofthings.ibmcloud.com";
pubTopic = "iot-2/type/" + DEVICE_TYPE + "/id/" + DEVICE_ID + "/cmd/test/fmt/String";
subTopic = "iot-2/type/+/id/+/evt/+/fmt/+";
authMethod = "a-910d3w-io5gxbfau6";
token = TOKEN;
clientId = "a:" + ORG + ":" + APP_ID;


def on_connect(mqttc, obj, flags, rc):
    print("rc: "+str(rc))

def on_message(mqttc, obj, msg):
    print(msg.topic+" "+str(msg.qos)+" "+str(msg.payload))

def on_publish(mqttc, obj, mid):
    print("mid: "+str(mid))

def on_subscribe(mqttc, obj, mid, granted_qos):
    print("Subscribed: "+str(mid)+" "+str(granted_qos))

def on_log(mqttc, obj, level, string):
    print(string)

mqttc = mqtt.Client(client_id=clientId)
mqttc.on_message = on_message
mqttc.on_connect = on_connect
mqttc.on_publish = on_publish
mqttc.on_subscribe = on_subscribe
mqttc.username_pw_set(authMethod, token)
mqttc.connect(server, 1883, 60)
mqttc.subscribe(subTopic, 0)


def ledControl( threadName, delay):
    while True:
        val = raw_input('Enter on or off ')
        if(val == "on"):
            mqttc.publish(pubTopic, "1")
        else:
            mqttc.publish(pubTopic, "0")

try:
    thread.start_new_thread( ledControl, ("ledControl", 0, ) )
except:
    print "Error: unable to start thread"

mqttc.loop_forever()
4.2.2 Result
 Figure: developed app subscribe temperature event from ESP32 IoT device

5. Using graph to display data
From IBM Watson IoT Platform dashboard chose BOARDS
Then choose USAGE OVERVIEW card and Add New Card
There are a lot of card types. You can choose one that is suitable with your expectation. In my case I will choose Line chart.
Choose the device that you want to draw its data.
Choose Connect new data set and choose the data that you want to show.
Choose the next options according to your expectation.
And here is the result.
Figure: Display data using graph
6. Using Alert Notification (to be updated)
The purpose of this service is to get early notification of application or service issues before they affect users.
Our demo has model:
Data from ESP32 IoT device will be sent to Watson IoT Platform to Node-RED and if there are any issues, they will be notified to Alert Notification Service.

In order to use this service, we create it here.
Here we bind our Alert Notification to the Node-RED service which we created before (in field Connect to).  Then we choose Restage button. And waiting until Restaging is finished.
From IBM Bluemix Dashboard click the Alert Notification row.
Then choose Service credentials in the top-left corner then choose New credential in the top-right corner and choose View credentials.
Here HTTP POST method will be used to push data to Alert Service.
Here is the Node-RED model
or you can Import the JSON content below to Node-RED and Deploy  the Node-RED model.
1
[{"id":"7e229960.957f78","type":"ibmiot in","z":"b1625c3.bcf8e2","authentication":"boundService","apiKey":"","inputType":"evt","deviceId":"","applicationId":"","deviceType":"+","eventType":"+","commandType":"","format":"json","name":"IBM IoT","service":"registered","allDevices":false,"allApplications":"","allDeviceTypes":true,"allEvents":true,"allCommands":"","allFormats":"","qos":0,"x":109.5,"y":260,"wires":[["c924ef3d.d5cc1"]]},{"id":"c924ef3d.d5cc1","type":"function","z":"b1625c3.bcf8e2","name":"temperature","func":"var temp = msg.payload.d.temperature;\nvar device = msg.payload.d.Name;\n\nvar upperThreshold = 30;\nvar lowerThreshold = 15;\n\n\nif ( temp > upperThreshold){\n\tmsg.payload = {\"Where\": String(device),\"What\":\"Temperature is too high: \"+Math.round(String(temp))+\" C\",\"Severity\":\"Fatal\"};\n\tmsg.reset = {\"reset\":0};\n\treturn [msg,msg.reset];\n}\n\nelse if (temp <= upperThreshold && temp >= lowerThreshold){\n msg.payload = {\"Where\": String(device),\"What\":\"Temperature is normal: \"+Math.round(String(temp))+\" C\",\"Severity\":\"Clear\"};\n return [null,msg];\n }\n\nelse if ( temp < lowerThreshold){\n msg.payload = {\"Where\": String(device),\"What\":\"Temperature is too low: \"+Math.round(String(temp))+\" C\",\"Severity\":\"Fatal\"};\n\tmsg.reset = {\"reset\":0};\n\treturn [msg,msg.reset];\n} ","outputs":1,"noerr":0,"x":286.5,"y":260,"wires":[["956a9a93.4b5fb"]]},{"id":"956a9a93.4b5fb","type":"http request","z":"b1625c3.bcf8e2","name":"post alert","method":"POST","ret":"obj","url":"https://ibmnotifybm.mybluemix.net/api/alerts/v1","tls":"","x":490.5,"y":404,"wires":[["e273ff52.d7e28"]]},{"id":"e273ff52.d7e28","type":"debug","z":"b1625c3.bcf8e2","name":"","active":true,"console":"false","complete":"payload","x":672.5,"y":257,"wires":[]}]
From IBM Bluemix Dashboard click the Alert Notification row and then choose Launch.
And choose Alert Viewer, you will see:
Figure: Alert Viewer GUI
7. Message Hub
Message Hub is based on Apache Kafka which is fast, scalable, and real-time messaging engine.
 Figure: Apche Kafka 
where: 
   - App can be your IoT devices, mobiles, ...
   - DB is a database
From the picture, you can imagine some features of this service:
   - Publish and subscribe (like message queue, pipelines) to streams of messages (app to app in real-time).
   - Store streams of messages in a fault-tolerant way (app to db).
   - Process streams of messages as they occur (process
the streams of data in real-time).
In this demo, I will show you how to use this service and bind it with Node-RED.
 Figure: Node-RED model of this demo
This demo has 4 nodes: message-hub in, an IBM IoT node (like top-App in picture above), message-hub out, debug node (like bottom-App in picture above).
In order to create Message Hub service, go here.
In "Connect to" choose our created Node-RED service. and waiting ...
Now we create Service credentials for our created Message Hub. From IBM Bluemix Dashboard, in Services box, choose Message Hub row.
Choose Service credentials and New credential:
In the Manage option, you can see 2options Grafana and Kibana. You can use them for GUI monitor.

Now we install message hub (in-out) node for our created Node-RED (the picture above). In order to do that we have to edit the "package.json" file of Node-RED.
From IBM Bluemix Dashboard choose Node-RED row and press the button in the Continuous Delivery box (bottom-right).
Fill your information and press Create:
Then choose Git box:
You will see a GUI like Github
Now click on the package.json row and choose Edit:
and Add this line to dependencies field: "node-red-contrib-messagehub-node":"*" and choose Commit changes below.
Now back to IBM Bluemix Cloud Foundry apps to restart Node-RED service:
After restarting, back to our Node-RED flow editor, you will see 2 new nodes messagehub (in-out). So just create the model as in the picture above:
And fill information in the message-hub node with the information which we created in the Message Hub Service credentials.
And enjoy the result in the Debug tab or in Kibana GUI:


Post a Comment

15 Comments

Anonymous said…
assertion "conn->state == NETCONN_CONNECT" failed: file "/Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/lwip/api/api_msg.c", line 1230, function: lwip_netconn_do_connected
abort() was called at PC 0x400d4b47 on core 1


I get this error. Anyone know how to fix?
Hi

you should give the full context of your situation.
But I think your app could not connect to somewhere
Unknown said…
Interesting post! This is really helpful for me. I like it! Thanks for sharing!
PHP developers Chennai | PHP developers in Chennai
Hi admin,

Do you have made some similar tests with AWS or AZURE?
I have to make a choice between IBM, Microsoft and Amazon. I already use Visual Studio and Visual micro (Arduino/ESP programming) and I'm very satisfied of them. IBM seem to be the most developed in term of graphical tool (Dashboard...), Amazone is the oldest Cloud (and IoT features too) in the market and Microsoft the biggest cloud (in 2017) and most important open source provider in the world (time is changing).
Personally, I'm very confident to Microsoft since 25 years and very interested by Azure (well integrated in Ms VS).
What do you think, do you have made some tests ?
Hi friend

I have used Azure (but not yet Amazon). I supported MS to make demos for Azure IoT in my country. I think Azure is better than IBM but the cost of Azure is quite expensive for me. So i used Azure trial license that is given by MS.

I am going to make tests for Amazon. And azure if I have trial license. :

Regards
Anonymous said…
Thank you for such an awesome post. Nice Blog

IoT Training in Chennai | IoT Courses in Chennai
venusha said…
Your Blog is really Nice and Informative..Thanks for sharing such a interesting article..keep updating..I really enjoy simply reading all of your weblogs. Simply wanted to inform you that you have people like me who appreciate your work.

Java Project Center in Chennai | Java Project Center in Velachery
UbiBot said…
Great article I would like it to share with
wireless temperature monitoring system team of UbiBot.
Praja said…
Thanks for the article. it helped me achieved what i was trying to do.
One thing i would say that ESP32 consumes more power and difficult to coordinate with the application.


Classroom IoT Training
maurya said…
Your post is really good. It is really helpful for me to improve my knowledge in the right way..
I got more useful information from this thanks for share this blog
scope of automation testing
scope of data science
how to improve english
common grammar mistakes
nodejs interview questions
pega interview questions