This
project demonstrates how to control your Arduino and ESP8266 module with Alexa
(Echo Dot) voice command, which implies that you can control many internet-of
Things including the palette light discussed below.
Again,
since I am not familiar with how to implement the MQTT protocol with the AT
command of ESP8266 module, I just try to go through the REST protocol to access
ThingSpeak rather than AWS/IoT, as well as the communication between AWS/Lambda
and ThingSpeak database. However, in this case we found another advantage of
taking the MQTT protocol, maintaining the data integrity. We have to guarantee
the data we write into ThingSpeak is what we want, especially for data
transmission between ThingSpeak and AWS/Lambda, although I did not do that.
Please note
that this article does not attempt to tell you how to implement the smart home
things, but rather to share with you that we can extend our scope and connect
more things that support the REST API, such as Wikipedia, Google map, Flickr,
some government’s database and etc.
The
Principle of Alexa Smart Palette
The concept of how to configure the palette light connected to our
Arduino (ESP8266) is illustrated below. First, a ‘Green’ color value is
uploaded to ThinhSpeak by making a HTTPS/GET request through a specific channel
(called LED Channel), when we invoke a voice command, something like ‘Alexa,
ask light config, set the light to green’ or ‘Alexa, ask light config, set red
to 80% and blue to 80%’ and etc., where the ‘light config’ is our Alexa Skill
APP. Second, our Arduino (ESP8266) query ThingSpeak database per about 15
seconds by making a HTTPS/GET request through the same channel, and then fetch
the RGB color tag described in a JSON format once we receive the response from
ESP-01. Finally, the palette light will be set based on the specified color tag
when it’s different from the previous setting, which acts as a direct control
to our Arduino (ESP-01) through voice command, as indicated by the orange arrows
in the figure below.
Please refer to the previous project ‘Alexa
Compliant Thermostat Implementation’ for more detail about the Arduino and
ASK program and how the REST protocol works between our Arduino(ESP8266) and
ThingSpeak IoT database.
Add a LED
Channel
In this project, we registered one new TingSpeak channel for color
configuration, as illustrated below. Here, we just need only one value (field1)
to store the color tag in hexadecimal format, e.g., 0xRRGGBB.
ASK and AWS/Lambda
Program Framework
For more detail about how to implement Alexa Skill setp by step, please
refer to my previous project named ‘The first
Alexa Skill – Hello World’. Assume our APP (Alexa Skill) name is ‘light
config’.
ASK/Intent Schema
I expect that user may invoke/ask ‘light config’ for a specific true
color light, enumerated in a custom defined variable type named COLOR_LIST,
e.g., red, green, blue, yellow and purple. Besides, we reserve another
invocation for users to adjust/mix RGB colors, by asking ‘light config’ with
different percentage values set to red, green and blue, respectively.
{
"intents": [
{
"intent": "TurnOnLightIntent"
},
{
"intent": "TurnOffLightIntent"
},
{
"slots": [
{
"name": "colorType",
"type": "COLOR_LIST"
}
],
"intent": "SetLightToIntent"
},
{
"slots": [
{
"name": "RedPercent",
"type": "NUMBER"
},
{
"name": "GreenPercent",
"type": "NUMBER"
},
{
"name": "BluePercent",
"type": "NUMBER"
}
],
"intent": "LightConfigIntent"
}
]
}
|
ASK/Sample Utterances
In order to improve the recognition of our new voice commands for Alexa,
which can trigger our custom intents successfully, we enumerate some possible
utterances.
TurnOnLightIntent turn on the light
TurnOffLightIntent turn off the light
SetLightToIntent set color to {colorType}
SetLightToIntent set the color to
{colorType}
SetLightToIntent set light to {colorType}
SetLightToIntent set the light to
{colorType}
LightConfigIntent set red to
{RedPercent}
LightConfigIntent set green to
{GreenPercent}
LightConfigIntent set blue to
{BluePercent}
LightConfigIntent set red to
{RedPercent} green to {GreenPercent} blue to {BluePercent}
LightConfigIntent set red to
{RedPercent} blue to {BluePercent}
LightConfigIntent set green to
{GreenPercent} blue to {BluePercent} red to {RedPercent}
LightConfigIntent set green to
{GreenPercent} red to {BluePercent}
LightConfigIntent set blue to
{BluePercent} red to {RedPercent} green to {GreenPercent}
LightConfigIntent set blue to
{BluePercent} green to {GreenPercent}
LightConfigIntent set red to
{RedPercent} percent
LightConfigIntent set green to
{GreenPercent} percent
LightConfigIntent set blue to
{BluePercent} percent
LightConfigIntent set red to
{RedPercent} percent green to {GreenPercent} percent blue to {BluePercent}
percent
LightConfigIntent set red to
{RedPercent} percent blue to {BluePercent} percent
LightConfigIntent set green to
{GreenPercent} percent blue to {BluePercent} percent red to {RedPercent}
percent
LightConfigIntent set green to
{GreenPercent} percent red to {BluePercent} percent
LightConfigIntent set blue to
{BluePercent} percent red to {RedPercent} percent green to {GreenPercent}
percent
LightConfigIntent set blue to
{BluePercent} percent green to {GreenPercent} percent
|
AWS/Lambda Script
Please refer to my previous project about ‘To access
ThingSpeak by making a HTTPS/GET request’, in which I utilize the
package proposed by Kathryn Hodge. First, you can download the Archive.zip
from her website and upload it to AWS/Lambda as a beginning. Second, you can
replace the index.js with the JavaScript described below. Please fill in your Channel
and APIKEY registered from ThingSpeak.
var request =
require("request");
// Called when the
user specifies an intent for this skill.
function onIntent(intentRequest,
session, callback) {
var intent = intentRequest.intent;
var intentName = intentRequest.intent.name;
// dispatch custom intents to handlers
here
if (intentName == "TurnOnLightIntent")
{
turnOnLightHandler(intent, session,
callback);
} else if (intentName == "TurnOffLightIntent")
{
turnOffLightHandler(intent, session,
callback);
} else if (intentName == "SetLightToIntent")
{
setLightToHandler(intent, session, callback);
} else if (intentName == "LightConfigIntent")
{
lightConfigHandler(intent, session,
callback);
} else if (intentName === 'AMAZON.HelpIntent') {
getWelcomeResponse(callback);
} else if (intentName === 'AMAZON.StopIntent' || intentName ===
'AMAZON.CancelIntent') {
handleSessionEndRequest(callback);
} else {
throw "Invalid intent";
}
}
// when APP is invoked
without intent
function getWelcomeResponse(callback)
{
var speechOutput = "Welcome! I am ready to configure your
light.";
var reprompt = speechOutput;
var header = "Light Configuration";
var shouldEndSession = false;
var sessionAttributes = {
"speechOutput" :
speechOutput,
"repromptText" : reprompt
};
callback(sessionAttributes,
buildSpeechletResponse(header,
speechOutput, reprompt, shouldEndSession));
}
// turn on light with
default white color
function
turnOnLightHandler(intent, session, callback) {
var speechOutput = "I'll turn on your light.";
var rgbVal = 0x00ffffff; // hexadecimal
format in 0x00RRGGBB
var reprompt = "Set RGB: " +
rgbVal.toString(16);
var url =
"https://api.thingspeak.com/update?api_key=APIKEY&field1=" +
rgbVal.toString(16);
request.get(url, function(error, response, body) {
var ret = JSON.stringify(body); // the current entry Id
reprompt = "The config colorCode
= " + rgbVal.toString(16);
callback(session.attributes,
buildSpeechletResponseWithoutCard(speechOutput,
reprompt, true));
});
}
// turn off light
function
turnOffLightHandler(intent, session, callback) {
var speechOutput = "I'll turn off your light.";
var rgbVal = 0x00000000; //
hexadecimal format in 0x00RRGGBB
var reprompt = "Set RGB:
" + rgbVal.toString(16);
var url =
"https://api.thingspeak.com/update?api_key=APIKEY&field1=" +
rgbVal.toString(16);
request.get(url, function(error, response, body) {
var ret = JSON.stringify(body); // the current entry Id
reprompt = "The config colorCode
= " + rgbVal.toString(16);
callback(session.attributes,
buildSpeechletResponseWithoutCard(speechOutput, reprompt, true));
});
}
// set light to a specific
color
function setLightToHandler(intent,
session, callback) {
var colorType = intent.slots.colorType.value;
var speechOutput = "Set the light to " + colorType + "
color.";
var rgbVal = 0x00000000; //
hexadecimal format in 0x00RRGGBB
switch ( colorType.toLowerCase() ) {
case 'red':
rgbVal = 0x640000; // RGB(100,0,0)
break;
case 'green':
rgbVal = 0x006400; // RGB(0,100,0)
break;
case 'blue':
rgbVal = 0x000064; // RGB(0,0,100)
break;
case 'yellow':
rgbVal = 0x646400; // RGB(100,100,0)
break;
case 'purple':
rgbVal = 0x640064; // RGB(100,0,100)
break;
default:
rgbVal = 0x000000; // turn-off
tri-LED
break;
}
var reprompt = "Set RGB: " + rgbVal.toString(16);
var url = "https://api.thingspeak.com/update?api_key=APIKEY&field1="
+ rgbVal.toString(16);
request.get(url, function(error, response, body) {
var ret = JSON.stringify(body); // the
current entry Id
reprompt = "The config colorCode
= " + rgbVal.toString(16);
callback(session.attributes,
buildSpeechletResponseWithoutCard(speechOutput, reprompt, true));
});
}
// config light with
specifying the R/G/B percentage
function
lightConfigHandler(intent, session, callback) {
var speechOutput = "Configure light with the specifying RGB to
";
var rPercent = 0; //intent.slots.RedPercent.value;
var gPercent = 0; //intent.slots.GreenPercent.value;
var bPercent = 0; //intent.slots.BluePercent.value;
var rgbVal = 0x00000000; //
hexadecimal format in 0x00RRGGBB
if ( intent.slots.RedPercent.value ) {
rPercent =
intent.slots.RedPercent.value;
rgbVal =
rgbVal|((rPercent>100?100:rPercent)*255/100)<<16;
speechOutput += "Red " +
rPercent +"%.";
}
if ( intent.slots.GreenPercent.value ) {
gPercent =
intent.slots.GreenPercent.value;
rgbVal = rgbVal|((gPercent>100?100:gPercent)*255/100)<<8;
speechOutput += " and Green
" + gPercent + "%.";
}
if ( intent.slots.BluePercent.value ) {
bPercent =
intent.slots.BluePercent.value;
rgbVal =
rgbVal|(bPercent>100?100:bPercent)*255/100;
speechOutput += " and Blue
" + bPercent + "%." ;
}
var url = "https://api.thingspeak.com/update?api_key=APIKEY&field1="
+ rgbVal.toString(16);
request.get(url, function(error, response, body) {
var ret = JSON.stringify(body); // the current entry Id
reprompt = "The config colorCode
= " + rgbVal.toString(16);
callback(session.attributes,
buildSpeechletResponseWithoutCard(speechOutput, reprompt, true));
});
}
// Route the incoming
request based on type (LaunchRequest, IntentRequest, etc.)
// The JSON body of
the request is provided in the event parameter.
exports.handler = function (event,
context) {
try {
console.log("event.session.application.applicationId=" +
event.session.application.applicationId);
if (event.session.new) {
onSessionStarted({requestId:
event.request.requestId}, event.session);
}
if (event.request.type ===
"LaunchRequest") {
onLaunch(event.request,
event.session,
function
callback(sessionAttributes, speechletResponse) {
context.succeed(buildResponse(sessionAttributes, speechletResponse));
});
} else if (event.request.type ===
"IntentRequest") {
onIntent(event.request,
event.session,
function
callback(sessionAttributes, speechletResponse) {
context.succeed(buildResponse(sessionAttributes, speechletResponse));
});
} else if (event.request.type ===
"SessionEndedRequest") {
onSessionEnded(event.request,
event.session);
context.succeed();
}
} catch (e) {
context.fail("Exception: "
+ e);
}
};
// Called when the
session starts.
function
onSessionStarted(sessionStartedRequest, session) {
// add any session init logic here
}
// Called when the
user invokes the skill without specifying what they want.
function onLaunch(launchRequest,
session, callback) {
console.log(`onLaunch requestId=${launchRequest.requestId},
sessionId=${session.sessionId}`);
getWelcomeResponse(callback);
}
// Called when the
user ends the session.
// Is not called when
the skill returns shouldEndSession=true.
function
onSessionEnded(sessionEndedRequest, session) {
}
function
handleSessionEndRequest(callback) {
const cardTitle = 'Session Ended';
const speechOutput = 'Light configuration done.';
const shouldEndSession = true;
callback({},
buildSpeechletResponse(cardTitle,
speechOutput, null, shouldEndSession));
}
// ------- Helper
functions to build responses for Alexa -------
function
buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
return {
outputSpeech: {
type: "PlainText",
text: output
},
card: {
type: "Simple",
title: title,
content: output
},
reprompt: {
outputSpeech: {
type: "PlainText",
text: repromptText
}
},
shouldEndSession: shouldEndSession
};
}
function
buildSpeechletResponseWithoutCard(output, repromptText, shouldEndSession) {
return {
outputSpeech: {
type: "PlainText",
text: output
},
reprompt: {
outputSpeech: {
type: "PlainText",
text: repromptText
}
},
shouldEndSession: shouldEndSession
};
}
function
buildResponse(sessionAttributes, speechletResponse) {
return {
version:
"1.0",
sessionAttributes: sessionAttributes,
response: speechletResponse
};
}
function capitalizeFirst(s) {
return s.charAt(0).toUpperCase() + s.slice(1);
}
|
Arduino
Board Connection
The wiring of our system board is based on the previous project about ‘Alexa
Compliant Thermometer implementation with ESP8266’, and add one more thing
-- the new palette LED. The R, G, B and GND petal on the LED module connect to
Arduino pin 10, 9, 11 and GND respectively.
Tri-LED Test
Please test your RGB LED first. It’s true that the Red and Blue are
misplaced in my LED module, so I switch then in my setTriLED procedure to keep
the red, green and blue parameters in order.
int redPin = 10; // R petal on
RGB LED module
int greenPin = 9; // G petal on RGB
LED module
int bluePin = 11; // B petal on RGB
LED module
// the color generating
function
void setTriLED(unsigned char red,
unsigned char green, unsigned char blue) {
analogWrite (redPin, blue); // yes, R and B
are misplaced in my LED module
analogWrite (greenPin, green);
analogWrite (bluePin, red); // yes, R and B
are misplaced in my LED module
}
void setup() {
}
void loop() {
setTriLED(100, 0, 0); // turn the RGB LED
red
delay(4000);
setTriLED(0,100, 0); // turn the RGB LED
green
delay(4000);
setTriLED(0, 0, 100); // turn the RGB LED
blue
delay(4000);
setTriLED(100,100,0); // turn the RGB LED
yellow
delay(4000);
setTriLED(128,0,200); // turn the RGB LED
purple
delay(4000);
color(0,0,0); // turn OFF
delay(5000);
}
|
Arduino
Program
In this example, the LCD is used to display the individual RGB
components set by the voice command. In the loop, we make a HTTPS/GET request through
ThingSpeak LED channel to read the latest color content and display it via the
LCD.
The color of the palette LED changes only when the latest color content
is different from the previous setting, and it will be stored as the new color
configuration. In this example, we send an intermittent request to ThingSpeak
every 10~15 seconds.
#include
<SoftwareSerial.h>
#include <LiquidCrystal_I
#define DEBUG 0
SoftwareSerial ESP(3, 2); //
ESP8266 ESP-01: Tx, Rx
// Addr, En, Rw, Rs, d4,d5,d6,d7 backlight, polarity
LiquidCrystal_I
// configuration for tri-LED
int redPin = 10; // R petal on
RGB LED module
int greenPin = 9; // G petal on RGB
LED module
int
bluePin = 11; //
B petal on RGB LED module
char
colorCode[8]="00000000"; // previous RGB
color code
bool
swState = 0; //
switch to enable/disable hunidity and temperature update
bool
wifiState = 0; // check wifi connection
const
char* ThingSpeakIP = "184.106.153.149";
const
char* ChannelID = ChannelID; //
Tri-LED Channel
const
char* ReadAPIKEY = APIKEY; // read
APIKEY
void
setup() {
Serial.begin(115200);
pinMode(7, INPUT_PULLUP); // set pin7 as the
interrupt button
// initialize LCD
lcd.begin(16, 2); // init LCD : 2 rows x 16 columns
lcd.backlight();
lcd.clear();
lcd.print("Hello World!");
delay(2000);
lcd.noBacklight(); // turn off back light and wait for user input
// initialize ESP-01
ESP.begin(115200);
delay(5000);
Serial.println("ESP-01 start
...");
// test the
correctness of RGB color
testTriLED();
#if !DEBUG
Serial.println("try to connect
ESP-01 to WAN (through home AP) ...");
if ( connectWAN("MOD
wifiState = 1;
Serial.println("press switch
button to start ...");
} else {
Serial.println("fail to join WAN
...");
}
#endif
}
void
testTriLED() {
setTirLED(100, 0, 0); // turn the RGB LED red
delay(1000);
setTirLED(0,100, 0); // turn the RGB LED green
delay(1000);
setTirLED(0, 0, 100); // turn the RGB LED blue
delay(1000);
setTirLED(100,100,0); // turn the RGB LED yellow
delay(1000);
setTirLED(128,0,200); // turn the RGB LED purple
delay(1000);
setTirLED(0,0,0); // turn off LED
}
void
setTirLED (unsigned char red, unsigned char green, unsigned char blue) {
analogWrite (redPin, blue); // yes, R and B are misplaced in my LED module
analogWrite (greenPin, green);
analogWrite (bluePin, red);
}
void
setRGBColor(char* rgbCode) {
repairColorCode(rgbCode);
if ( strcmp(rgbCode,colorCode)==0 ) {
//Serial.println("<<no
change>>");
return;
}
strcpy(colorCode,rgbCode);
unsigned long val = (unsigned
long)strtoul(rgbCode,NULL,16)&0x00ffffff;
unsigned char r = (unsigned
char)(val>>16);
unsigned char g = (unsigned
char)(val>>8);
unsigned char b = (unsigned char)(val);
setTirLED(
(unsigned char)r,
(unsigned char)g,
(unsigned char)b
);
// display RGB color
factor
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("R:" + String(r)); // Red
lcd.setCursor(8, 0);
lcd.print("G:" + String(g)); // Green
lcd.setCursor(0, 1);
lcd.print("B:" + String(b)); // Blue
setDelay(5000); //
display 5 seconds
lcd.noBacklight(); // turn off LCD
}
void repairColorCode(char*& code) {
if (
code!=NULL ) {
int len = strlen(code);
for ( int ii=0; ii<len; ii++ ) {
if( code[ii]>'f' )
code[ii] = 'f';
}
}
}
bool
connectWAN(char* ssidName, char* passWord) {
String joinCmd =
"AT+CWJAP=\"" + String(ssidName) + "\",\""
+ String(passWord) + "\"\r\n";
String recMsg;
int status = false;
sendATcmd("AT+RST\r\n",2000,recMsg); // reset ESP-01
sendATcmd("AT+CWMODE=1\r\n",1000,recMsg);
// config ESP-01 as STA mode
sendATcmd(joinCmd,1000,recMsg); // wait the server to ack "OK"
for (int loop=0; loop<10; loop++ ) { // wait
AP's response
Serial.print(".");
if ( ESP.find("OK") ) {
status = true;
Serial.println("join ESP-01
to WAN success ...");
break;
}
setDelay(1000);
}
//Serial.println(recMsg);
return status;
}
void
setDelay(unsigned int ms) {
unsigned long timeout = ms + millis();
while ( millis()<timeout ) {
checkSwitchButton();
}
}
bool
checkSwitchButton() {
if ( digitalRead(7)==LOW ) {
swState = !swState;
Serial.println("\nInterrupt:
Switch Button = " + String(swState) );
delay(300); //
debounce delay (depending on your behavior)
}
return swState;
}
// +IPD,68:{"crdated_at":"
char*
jsonGetColorCode(String& inMsg, char (&code)[8]) {
// repair ESP-01 one
bit received char error
inMsg.replace(';',':'); // repair ESP-01
error buffer, e.g., field1":"ffff00" -->
field1";"ffff00"
inMsg.replace('#','\"'); // repair ESP-01 error buffer, e.g.,
field1":#ffff00" --> field1";"ffff00"
char* msg = inMsg.c_str();
char* p1;
char* p2;
if (
(p1=strstr(msg,"+IP"))==NULL ||
(p2=strstr(msg,"CLOS"))==NULL ) {
Serial.println("Error! fail to fetch JSON data.");
return NULL;
}
if ( (p1=strchr(msg,'{'))==NULL ) {
Serial.println("Error! fail to
fetch JSON data.");
return NULL;
}
msg = p1;
*(p2) = '\0'; //
end JSON
// fetch color value
in JSON, e.g., ... "field1":"ffff00"}
if ( (p1=strrchr(msg,':'))!=NULL ) {
msg = p1+2; // trim the 1st
bracket
*(p2-2) = '\0'; // trim the 2nd bracket
if ( strlen(msg)>8 ) // invalidated color code
strcpy(code,"00000000");
else
strcpy(code,msg);
}
return code;
}
void
sendATcmd(String cmd, unsigned int msDelay, String& outEspMsg) {
unsigned long timeout = millis() +
msDelay;
Serial.print(">>ESP-01: "
+ String(cmd)); // debug
ESP.print(cmd); // send AT command to
ESP-01
// allow delay >
msDelay if ESP-01 still receives message
outEspMsg = "";
while ( ESP.available() ||
millis()<timeout ) {
while ( ESP.available() ) {
char ch = ESP.read();
outEspMsg += ch;
}
}
}
// query data from ThingSpeak
void
queryThingSpeak(const char* ipName, const
char* channelName, const char* apiKey, String& outEspMsg) {
String tcpCmd =
"AT+CIPSTART=\"TCP\",\"" + String(ipName) +
"\",80\r\n";
String getCmd = "GET
/channels/" + String(channelName) +
"/feeds/last.json?key="
+ String(apiKey) + "\r\n";
String cipCmd = "AT+CIPSEND=" +
String(getCmd.length()) + "\r\n";
sendATcmd(tcpCmd,1000,outEspMsg); // ask HTTP
connection, and wait the server to ack "OK"
sendATcmd(cipCmd,2000,outEspMsg); // start CIPSEND
request, and wait the server to ack "OK"
sendATcmd(getCmd,3000,outEspMsg); // send GET
request and receive response
Serial.println(outEspMsg);
}
void
loop() {
#if DEBUG // ESP-01 debug by using AT command through serial console
if
( Serial.available() ) {
ESP.write( Serial.read() );
}
if ( ESP.available() ) {
Serial.write( ESP.read() );
}
#else
if ( swState && wifiState
&& dataCnt < 100 ) {
// query the
triLED color from ThingSpeak
Serial.println("query the triLED
color from ThingSpeak ...");
String recMsg;
queryThingSpeak(
ThingSpeakIP, // ThingSpeak IP
ChannelID, // channelId
(Alexa channel)
ReadAPIKEY, // read API-KEY
(Alexa channel)
recMsg // received
message from ThingSpeak
);
char code[8]="00000000";
if (
jsonGetColorCode(recMsg,code)!=NULL ) {
setRGBColor(code);
}
Serial.println("press switch to
stop (will start after one minute) ...");
if ( swState )
setDelay(5000); // update humidity and temperature 5 second
}
#endif
setDelay(500); //
monitor hardware interrupt
}
|
Test Steps:
(Note: ‘light config’ is the APP name of my Alexa Skill, and first of
all, we configure our palette light with a specific true color.)
Author: Alexa, ask light config, set the light to blue.
Author: Alexa, ask light config, set the light to yellow.
Author: Alexa, ask light config, set the light to red.
(Note: In this moment, AWS/Lambda fail to write ThingSpeak, while our
ESP module is trying to read color from ThingSpeak at the same time. So, it
would be better to check the write data correctness again by querying
ThingSpeak through the same channel.)
(Note: Second, we test the palette light by specifying individual RGB
color component.)
Author: Alexa, ask light config.
Author: Set red to 80% and green to 80%.
(Note: It’s correct yellow color.)
Author: Set red to 20% and green to 50%.
Author: Set blue to 100%.
Issue
Discussion
We have found that the write data access of AWS/Lambda to ThingSpeak may
fail when ESP module is also trying to perform read access to ThingSpeak
through the same channel. It would be better to make a confirmation for each
data sent to IoT database, for example, to query, compare and re-write the date
if it is inconsistent to ensure the data correctness.
An improved approach for data confirmation between AWS and ThingSpeak
through the LED channel is illustrated below. The data request from ESP-01 to
ThingSpeak is intermittent, and we also allow non-immediate data updates, so
the problem is not great.
Another potential problem is respond quality of the IOT database to the
client service, and the client service may also be affected by the network
bandwidth and the number of client requests. We sometimes encounter that the
IoT database is too slow to response our hardware's request, which may lead to
a data fetch error.
It's not difficult to customize your own IoT database to improve the
transmission quality and performance, since we connect Things though the REST
protocol. Of course, we can implement our own IoT database within the
AWS/Lambda environment as well, such that we can guarantee the data consistency
coming from AWS/Lambda. On the other hand, once the data is updated, the custom
IoT database can intermittently notify our system, which can be configured to
listen on TCP port 1883 without going out and making TCP requests.
Interestingly, when we continue to clarify all the problems and try to
fix some of them, the data transfer/operation of entire system seems to be more
and more like the MQTT protocol. It may be said that the emergence of MQTT is
like an inevitable result evolved gradually in order to continue to solve the
problem. In other words, you should invent it as well even if IBM engineers do
not invent it.