HTTP

Is this section, we will modify the simple sketch that measures just temperature and humidity that we made in Chapter 2, to send data to an Azure Function directly using HTTP. For convenience, the sketch is repeated below (DHT22 sensor connected to D1):

// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_DHT.h>

#define DHTPIN 1     // what pin we're connected to

#define DHTTYPE DHT22        // DHT 22 (AM2302)

// Variables for humidity and temperature
double h, t;

DHT dht(DHTPIN, DHTTYPE);

void setup() {
    dht.begin();

    // Setup Particle variables
    Particle.variable("temperature", t);
    Particle.variable("humidity", h);
}

void loop() {
    // Wait a few seconds between measurements.
    delay(10000);

    // Reading temperature or humidity takes about 250 milliseconds!
    // Sensor readings may also be up to 2 seconds 'old' (its a 
    // very slow sensor)
    h = dht.getHumidity();
    // Read temperature as Celsius
    t = dht.getTempCelcius();

    // Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t)) {
        return;
    }

    // Publish to Particle
    Particle.publish("temperature", String(t), 60, PRIVATE);
    Particle.publish("humidity", String(h), 60, PRIVATE);

}

Create a new app in Particle Build, include the AdaFruit_DHT library, and paste the code above in the app (avoid a double #include at the top). Flash the app to your Photon and verify that you get the temperature and humidity events.

Before adding device code, let's create an Azure Function that can pick up the temperature and humidity values and log them. You already created an Azure Function in Chapter 1 so I will not repeat all the steps in detail:

  • Open the Function App you created earlier or create a new Function App
  • Create a new function of type HttpTrigger-JavaScript and call it HttpParticleTrigger
  • In Authorization level, choose Function

The function code expects temperature and humidity to be sent in a Json body and only requires a small modification to the sample code of the function:

module.exports = function (context, req) {
    if (req.body.temperature && req.body.humidity) {
        context.res = {
            // status: 200, /* Defaults to 200 */
            body: "Received " + req.body.temperature + " and " + req.body.humidity
        };
        context.log("Temperature=" + req.body.temperature + ", Humidity=" + req.body.humidity);
    }
    else {
        context.res = {
            status: 400,
            body: "Please pass temperature and humidity in body"
        };
    }
    context.done();
};

You can test the function in the browser with a correctly formed body:

Now that we know our function works, we should test it from our local machine. But first, we need to find out the URL to connect to and that is very easy: just click the Get function URL as shown in the screenshot above. You will get someting like below (on one line, replace function-app with the name of your Function App):

https://function-app.azurewebsites.net/api/HttpParticleTrigger?
    code=PHC2bZX9awOlvoAt29BUTPsjWe7YmlOXeuTsys62q0arzHf2wNfbDQ==

Now you can use Postman or cURL to test the function. With cURL (https URL on one line, replace function-app):

curl -H "Content-Type: application/json" -X POST -d '{"temperature":28.9,"humidity":40.2}' 
    https://function-app.azurewebsites.net/api/HttpParticleTrigger?
    code=WFYE2oFZ1XnScqhbBRhcuB20OyUeDvTlqbajw9X718EkYPytRgscOg==

Because we created the function with the Function authorization level, we have to pass a code (or function key). You can manage these function keys from the Azure Portal. With the above cURL command, you should get the following response:

"Received 28.9 and 40.2"

Now that we know our function is working, it is time to change our Particle app. We need to modify the app in two ways:

Formatting temperature and humidity is easy with SparkJson as we have seen before:

// This #include statement was automatically added by the Particle IDE.
#include <SparkJson.h>

// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_DHT.h>

#define DHTPIN 1 // what pin we're connected to

#define DHTTYPE DHT22 // DHT 22 (AM2302)

// preallocated memory to reserve on the stack; use 200 bytes
StaticJsonBuffer<200> jsonBuffer;

// create a JSON object
JsonObject& root = jsonBuffer.createObject();

// Variables for humidity and temperature
double h, t;

DHT dht(DHTPIN, DHTTYPE);

void setup() {
    dht.begin();

    // Setup Particle variables
    Particle.variable("temperature", t);
    Particle.variable("humidity", h);
}

void loop() {
    // Wait a few seconds between measurements.
    delay(10000);

    // Reading temperature or humidity takes about 250 milliseconds!
    // Sensor readings may also be up to 2 seconds 'old' (its a
    // very slow sensor)
    h = dht.getHumidity();
    // Read temperature as Celsius
    t = dht.getTempCelcius();

    // Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t)) {
        return;
    }

    // fill JsonObject
    root["humidity"]=h;
    root["temperature"]=t;

    // generate the JSON string
    char output[200];
    root.printTo(output, sizeof(output));

    // Publish to Particle
    Particle.publish("env", output, 60, PRIVATE);

}

In the above app, the Json object is sent to the Particle Cloud to easily check the result. Now that serialization to Json works, let's turn to writing some device code to do a HTTP POST.

The device code we need to write, depends on whether we decide to use HTTP or HTTPS. Naturally, because we use an authorization key in the request, we should use HTTPS. In that case, you can try to use the httpsclient-particle library which uses the open source MatrixSSL implementation. I said "try to use" because using the library usually results in a device panic, causing the device to restart. Many libraries are created by developers as a side project and could be unstable. When prototyping, that is usually fine. In production however, do not use such libraries.

Now that we know the difficulty of using HTTPS, let's see how to do unencrypted communication. Later, I will show you a solution to use HTTPS with Particle Webhooks which is the recommended approach with Particle. For HTTP requests you can use HttpClient, which is a very simple library to use. Note that the HttpClient library is also still a work in progress. To use the HttpClient library, you need to include it in your app and also include application.h by adding the line below to your code:

#include "application.h"

Next, you need to define a variable of type HttpClient and define the headers:

// http client
HttpClient http;

// define headers for request
http_header_t headers[] = {
    { "Content-Type", "application/json" },
    { "Accept" , "application/json" },
    { NULL, NULL } // NOTE: Always terminate headers will NULL
};

In the headers variable, we tell the server we want to work with the application/json content type. Next, we need variables for the request and response:

// variables for http request and response
http_request_t request;
http_response_t response;

To actually perform the HTTP POST, use the code below which configures the requests and then sends it using http.post:

// http request
request.hostname = "func-app.azurewebsites.net";
request.port = 80;
request.path = "/api/func-name?code=WFYE2oFZ1XnScqhbBRhcuB20OyUeDvTlqbajw9X718EkYPytHujcOg==";
request.body = output;
http.post(request, response, headers);

Replace func-app with the Function App name, func-name with the name of your Azure Function and the authorization code with your own code.

The full app is shown below:

#include "application.h"

// This #include statement was automatically added by the Particle IDE.
#include <HttpClient.h>

// This #include statement was automatically added by the Particle IDE.
#include <SparkJson.h>

// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_DHT.h>

#define DHTPIN 1 // what pin we're connected to

#define DHTTYPE DHT22 // DHT 22 (AM2302)

// preallocated memory to reserve on the stack; use 200 bytes
StaticJsonBuffer<200> jsonBuffer;

// create a JSON object
JsonObject& root = jsonBuffer.createObject();

// Variables for humidity and temperature
double h, t;

DHT dht(DHTPIN, DHTTYPE);

// http client
HttpClient http;

// define headers for request
http_header_t headers[] = {
    { "Content-Type", "application/json" },
    { "Accept" , "application/json" },
    { NULL, NULL } // NOTE: Always terminate headers will NULL
};

// variables for http request and response
http_request_t request;
http_response_t response;

void setup() {
    dht.begin();

    // Setup Particle variables
    Particle.variable("temperature", t);
    Particle.variable("humidity", h);
}

void loop() {
    // Wait a few seconds between measurements.
    delay(10000);

    // Reading temperature or humidity takes about 250 milliseconds!
    // Sensor readings may also be up to 2 seconds 'old' (its a
    // very slow sensor)
    h = dht.getHumidity();
    // Read temperature as Celsius
    t = dht.getTempCelcius();

    // Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t)) {
        return;
    }

    // fill JsonObject
    root["humidity"]=h;
    root["temperature"]=t;

    // generate the JSON string
    char output[200];
    root.printTo(output, sizeof(output));

    // http request
    request.hostname = "func-app.azurewebsites.net";
    request.port = 80;
    request.path = "/api/func-name?code=WFYE2oFZ1XnScqhbBRhcuB20OyUeDvTlqbajw918EkYPytRtjcOg==";
    request.body = output;
    http.post(request, response, headers);

    // Publish to Particle
    Particle.publish("httpresponse", String(response.status), 60, PRIVATE);

}

In the above code, the HTTP response is published to Particle Cloud to make it easy to verify the status of the HTTP POST. In the logs of the Azure Function, you can check the result as well.

Great, HTTP is working fine. To get HTTPS to work, Particle has an interesting solution with its support for Webhooks. All you need to do is send the Json with Particle.publish(). Next, create a webhook integration that forwards the event data to its destination. This method is the most reliable and also the simplest.

To try it, create a new app in Particle Build called httpsapp and include the SparkJson and Adafruit_DHT libraries. Then use the following code:

// This #include statement was automatically added by the Particle IDE.
#include <SparkJson.h>

// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_DHT.h>

#define DHTPIN 1 // what pin we're connected to

#define DHTTYPE DHT22 // DHT 22 (AM2302)

// preallocated memory to reserve on the stack; use 200 bytes
StaticJsonBuffer<200> jsonBuffer;

// create a JSON object
JsonObject& root = jsonBuffer.createObject();

// Variables for humidity and temperature
double h, t;

DHT dht(DHTPIN, DHTTYPE);

void setup() {
    dht.begin();

    // Setup Particle variables
    Particle.variable("temperature", t);
    Particle.variable("humidity", h);


}

void loop() {
    // Wait a few seconds between measurements.
    delay(10000);

    // Reading temperature or humidity takes about 250 milliseconds!
    // Sensor readings may also be up to 2 seconds 'old' (its a
    // very slow sensor)
    h = dht.getHumidity();
    // Read temperature as Celsius
    t = dht.getTempCelcius();

    // Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t)) {
        return;
    }

    // fill JsonObject
    root["humidity"]=h;
    root["temperature"]=t;

    // generate the JSON string
    char output[200];
    root.printTo(output, sizeof(output));

    Particle.publish("envhook", output, 60, PRIVATE);

}

Now, from the Particle Console, create a new Webhook integration that sends custom JSON data. The Azure Function only requires temperature and humidity in the Json object.

When your device publishes the envhook event, the Webhook integration makes a request to the Azure Function using HTTPS and sends the expected JSON body. Both the connections from the device to Particle Cloud and from Particle Cloud to the Azure Function are encrypted. Note that there are limitations to the use of Webhooks and they can be found in the Particle Docs. An important limit is the maximum amount of webhook invocations per minute per device which is set to ten.

results matching ""

    No results matching ""