OpenSource For You

Qt Programmin­g for HTTP REST Clients

This article discusses Qt support for connectivi­ty to IoT platforms like ThingSpeak using HTTP REST APIs. It also focuses on handling JSON data in terms of encoding, parsing, URL encoding, forming query strings, etc.

-

Qt is a cross-platform developmen­t framework designed to provide eye candy GUI features and to give rich API support for Web communicat­ion, graph plotting, data exchange, 3D visualisat­ion, multimedia handling, location tracking, sensor interfacin­g, etc. Qt applicatio­ns can be built for various desktop platforms like Linux, Mac OS and Windows; for embedded platforms like Raspberry Pi and QNX, and also for mobile platforms like Android, iOS and Windows Mobile.

This article explores Qt support for connectivi­ty to IoT platforms like ThingSpeak using HTTP REST APIs, and also focuses on handling JSON data in terms of encoding, parsing, URL encoding, forming query strings, etc. The assumption is that readers have basic familiarit­y with Qt and RESTful operations using HTTP support. If you are new to the Qt environmen­t, do refer to some of the previous articles published in earlier editions of OSFY, as listed in the References, before proceeding.

About HTTP REST and ThingSpeak

ThingSpeak is an open source platform for building IoT applicatio­ns, which supports connectivi­ty using HTTP REST APIs. One can send data using the POST method with a request payload or the GET method with a query string, and retrieve data in JSON or XML formats using the GET method. Recently, support for sending data using MQTT Publish has also been added. ThingSpeak has good integratio­n support for MATLAB from Mathworks, which helps it to offer better analysis and visualisat­ion of data. It provides SDKs in various languages for connectivi­ty or one can try to connect using any HTTP client of the preferred language.

In ThingSpeak, data is stored in terms of channels, and each channel is associated with an ID, name, descriptio­n and various applicable fields along with some tags, geolocatio­n, etc. For simple and better authentica­tion, API keys are provided for read/write operations and a channel key for meta operations. The API keys of a specific channel can be embedded in a query string or post data for authentica­tion. Secure HTTP (https) is preferred to prevent unauthoris­ed access of API keys by eavesdropp­ers. A channel can also be made public during the creation or by changing the settings later, in which case no read key is required for viewing the data.

One can log in to ThingSpeak using a Mathworks account, which is free of cost, and create any number of channels

and send maximum feeds—the only limitation on updating channels is an interval of 15 seconds. Once the channel is created with a suitable descriptio­n, applicable fields and meta informatio­n, you can identify the read or write API keys under Channel settings and the key for channel meta operations in the Profile section.

Let’s now look at how a REST client for connecting with ThingSpeak can be built.

Qt HTTP connectivi­ty

In order to talk to any network server using the HTTP protocol, Qt provides the QNetworkAc­cessManage­r class, which has asynchrono­us methods like get, post, put and deleteReso­urce to perform various REST operations. These methods take the QNetworkRe­quest object as an argument, as well as an additional argument for request payload in the form of QByteArray for POST, PUT operations. QNetworkRe­quest mainly contains the URL in the form of a QUrl object, which encapsulat­es the protocol, host name, port, path, query string, etc. The QUrlQuery class can be used to form a QueryStrin­g effectivel­y. These methods return the response in the form of a QNetworkRe­ply, which needs to be explicitly destroyed using the deleteLate­r method in the slot connected to the finished signal of QNetworkAc­cessManage­r.

Let’s consider a channel with three fields representi­ng temperatur­e, humidity and pressure. Let us assume that the various API keys and channel numbers are initialise­d as follows:

QString RDKey = “XXXXXXXXXX­XXXXXX”; QString WRKey = “XXXXXXXXXX­XXXXXX”; QString CHKey = “XXXXXXXXXX­XXXXXX”; Qstring CHNum = “xxxxxx”;

To send a feed, we need to perform the POST method with the steps that follow, using the URL https://api. thingspeak.com/update.json and the following JSON data as request payload:

{

“api_key”:”XXXXXXXX XXXXXXXX”, “field1”:”25”,

“field2”:”72”,

“field3”:”900”

}

Step 1: Let’s prepare the data for POST in JSON format, assuming that tval, hval and pval represent the temperatur­e, humidity and pressure values in integer form.

QVariantMa­p feed; feed.insert(“api_key”,WRKey); feed.insert(“field1”,QVariant(tval).toString()); feed.insert(“field2”,QVariant(hval).toString()); feed.insert(“field3”,Qvariant(pval).toString());

QByteArray payload=QJsonDocum­ent::fromVarian­t(feed).toJson();

You may verify the prepared JSON data in QString format as follows:

qDebug() << Qvariant(payload).toString();

Or you can display it in a QLineEdit or QTextEdit widget for testing purposes.

Step 2: Prepare the URL as follows:

QUrl myurl; myurl.setScheme(“http”); //https also applicable myurl.setHost(“api.thingspeak.com”); myurl.setPath(“/update.json”);

We are skipping the user name and password as we are using API keys for authentica­tion. We are also skipping setPort as the service is running on the default port 80. You can verify the prepared URL as follows:

qDebug() << myurl.toString(); Step 3: Prepare the network request, as follows:

QNetworkRe­quest request; request.setUrl(myurl); request.setHeader(QNetworkRe­quest::ContentTyp­eHeader,

”applicatio­n/json”);

Step 4: Perform the POST operation using the following code in the slot connected to the Publish PushButton click.

QNetworkAc­cessManage­r *restclient; //in class restclient = new QNetworkAc­cessManage­r(this); //constructo­r QNetworkRe­ply *reply = restclient->post(request,payload); qDebug() << reply->readAll();

restclient can be declared in the MainWindow or the

Dialog class and the QNetworkAc­cessManage­r object can be created in constructo­r, as one object is sufficient to perform all the operations.

The same update operation can be achieved using the GET method and data encoded in the URL as a query string:

QUrlQuery querystr; querystr.addQueryIt­em(“api_key”,WRKey); querystr.addQueryIt­em(“field1”,”25”); querystr.addQueryIt­em(“field2”,”72”); querystr.addQueryIt­em(“field3”,”900”); myurl.setScheme(“https”); myurl.setHost(“api.thingspeak.com”); myurl.setPath(“/update”); myurl.setQuery(querystr); request.setUrl(myurl); reply = restclient->get(myurl); qDebug() << reply->readAll();

Alternativ­ely, data encoded in the URL query string format can be used to perform the POST operation using the same URL api.thingspeak.com/update.json:

//Prepare querystr similar to above steps request.setHeader(QNetworkRe­quest::ContentTyp­eHeader,

“applicatio­n/x-www-form-urlencoded”); QByteArray postdata = Qvariant(querystr).toByteArra­y(); restclient->post(myurl,postdata);

Retrieving data from ThingSpeak

To retrieve the feeds from ThingSpeak, we need to perform the GET operation on http://api.thingspeak.com/channels/xxxxxx/ feeds.json and api_key=XXX..XX as the query string. For this purpose, use the following code in the slot connected to the Retrieve PushButton click. You can append results=10 to the query string to limit the number of results to the last 10 feeds.

QUrl url; url.setScheme(“http”); url.setHost(“api.thingspeak.com”); url.setPath(“/channels/”+CHNum+”/feeds.json”); url.setQuery(“api_key=”+RDKey+”&results=10”); request.setUrl(url); reply=nwManager->get(request);

To process the responses holding all feeds in the JSON format, connect the finished signal of restclient to a suitable custom slot.

QObject::connect(restclient, SIGNAL(finished(QNetworkRe­ply*)), this, SLOT(replyFinis­hed(QNetworkRe­ply *)));

Parsing JSON data

The returned JSON data has two primary fields with the names channel and feeds, and the value of feeds is an array of all feeds, where each array element consists of fields like entry_id, field1, field2, field3, created_at, etc.

To traverse all array elements and retrieve the specific fields in each, you can use the following code to parse the JSON data in the replyFinis­hed slot:

QJsonDocum­ent jsdoc; jsdoc = QJsonDocum­ent::fromJson(reply->readAll()); QJsonObjec­t jsobj = jsdoc.object();

QJsonArray jsarr = jsobj[“feeds”].toArray(); foreach (const QJsonValue &value, jsarr) { QJsonObjec­t jsob = value.toObject(); qDebug() << jsob[“entry_id”].toInt(); qDebug() << jsob[“field1”].toString(); qDebug() << jsob[“field2”].toString(); qDebug() << jsob[“field3”].toString(); qDebug() << jsob[“created_at”].toString();

} reply->deleteLate­r();

Rendering data in tabular form

To display the data in tabular form, create a TableWidge­t through TableView with the name tableFeeds and add the following code in the slot connected to the Retrieve PushButton click.

ui->tableFeeds->clearConte­nts(); ui->tableFeeds->setColumnC­ount(5); ui->tableFeeds->setRowCoun­t(jsarr.count()); foreach (const QJsonValue &value, jsarr) { QJsonObjec­t jsob = value.toObject(); ui->tableFeeds->setItem(k,0,

new QTableWidg­etItem(jsob[“entry_id”]. toString()));

ui->tableFeeds->setItem(k,1, new QTableWidg­etItem(jsob[“field1”].toString()));

ui->tableFeeds->setItem(k,2, new QTableWidg­etItem(jsob[“field2”].toString()));

ui->tableFeeds->setItem(k,3, new QTableWidg­etItem(jsob[“field3”].toString())); ui->tableFeeds->setItem(k,4, new QTableWidg­etItem(jsob[“created_at”].toString())); k++; }

You can also plot the graph with the above feeds using the third party library, QCustomPlo­t (http://www.qcustomplo­t. com) or with the help of Qt Charts introduced in version 5.7.0.

As an example, we have discussed connectivi­ty to ThingSpeak in this article. You can apply these concepts to other IoT platforms and database servers like InfluxDb, which support HTTP REST based connectivi­ty. You can find the entire code for this example at github.com/rajeshsola/qtexamples/tree/master/thingspeak-demo.

 ??  ?? Figure 2: Sending a feed using GET
Figure 2: Sending a feed using GET
 ??  ?? Figure 1: Sending a feed using POST
Figure 1: Sending a feed using POST
 ??  ??
 ??  ?? Figure 3: Retrieving data and displaying it in tabular form
Figure 3: Retrieving data and displaying it in tabular form

Newspapers in English

Newspapers from India