Institute of Computer Science
  1. Courses
  2. 2020/21 fall
  3. Mobile Computing and Internet of Things (LTAT.06.009)
ET
Log in

Mobile Computing and Internet of Things 2020/21 fall

  • Main
  • Lectures
  • Labs
  • Homeworks & Home Assignments
  • Quizes
  • Task submission
  • Extra Materials
  • Projects
    • Teams & Topics
    • Presentations & Report
    • Grading & Submission

Lab 12 - Thingspeak platform

From ThingSpeak/MathWorks documentation:

ThingSpeak is an IoT analytics platform service that allows you to aggregate, visualize, and analyze live data streams in the cloud. You can send data to ThingSpeak™ from your devices, create instant visualizations of live data, and send alerts using web services like Twitter® and Twilio®. With MATLAB® analytics inside ThingSpeak, you can write and execute MATLAB code to perform preprocessing, visualizations, and analyses. ThingSpeak enables engineers and scientists to prototype and build IoT systems without setting up servers or developing web software.

Set-up

Create a Thingspeak account.
Note: Free accounts are limited to 4 channels and the maximum rate of sending data is at 15 second intervals

Part 1 - Sending data to Channels

In ThingSpeak, data is organized into Channels. A channel contains several fields. Fields hold the values (numeric or non-numeric). For example, you may have something like:

Channel: Living Room
  • Field 1 : Temperature
  • Field 2 : Humidity
  • Field 3 : CO2
  • Field 4 : Door magnet sensor
  • Let's first set up a new channel. Follow the official tutorial.
    • Set field 1 to have name "Magnetic sensor"

Data can be written & read to/from a channel via HTTP or MQTT. The HTTP supports several ways of sending data.

The most basic way of sending data to Thingspeak:

Send Data to Channel with GET ( Doc ):

REQUEST:
GET https://api.thingspeak.com/update?api_key=<<my_api_key>>&fieldX=<<fieldX_value>>
RESPONSE:
The entry ID of the update (e.g., 18) or 0 if it failed.
  • Try out sending numeric values to field 1 by making the request from your browser (or use Postman, cURL, etc if you prefer).

After Sending data, you should notice the values appear in the Channels Private/Public view Thingspeak visualization:


Using the ESP32 in-built Hall Sensor

Let's write some Arduino code to read values from the hall effect sensor that is built in to ESP32. This sensor measures magnitude of magnetic field.

  • To get a feel for how the sensor works, it's recommended to first try out the pre-existing Arduino IDE example: File -> Examples -> ESP32 -> HallSensor
    • If you don't have magnets at hand (e.g. a fridge magnet), you can for example use the speaker of your smartphone as a magnet. However, since such a small speaker is a rather weak magnet and the Hall Sensor can be quite noisy, you should try taking an average of mulitple readings to more clearly see the changes in magnetic field.

Show Code for averaged hall sensor values

  int h;
  double hallAverage;
  void loop() {
    // Take an average of 1000 readings over a period of 100 milliseconds.
    h = 0;
    for (int i=0;i<1000;i++) {
      h += hallRead();
      delayMicroseconds(100);
    }
    hallAverage = (double) h / 1000.0;
  }


Making HTTP requests from ESP32.

Now, let's start sending these values to ThingSpeak with HTTP.

  • Install the library ArduinoHttpClient from Library Manager, it makes writing HTTP requests more convenient.
  • Import the WiFi and ArduinoHttpClient libraries (at the top of your Arduino code):
    #include <WiFi.h>
    #include <ArduinoHttpClient.h>
  • At the beginning of the code, define these constants and update their values:
const char* ssid     = "SOME_WIFI_SSID";
const char* password = "SOME_WIFI_PASSWORD";

const char serverAddress[] = "api.thingspeak.com";
const char* apikey = "YOUR_THINGSPEAK_API_KEY_HERE";
  • Initialize the WiFi connection when device boots with the following:
    • Show Code
WiFiClient wifi;

void setup() {
  Serial.begin(115200); 
  Serial.println("Attempting to connect to Network named: ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while ( WiFi.status() != WL_CONNECTED) {
    // Connect to WPA/WPA2 network: 
    Serial.print(".");
    delay(500);
  }

  // print the SSID of the network you're attached to:
  Serial.println("Connected to SSID: " + WiFi.SSID());
  Serial.print("IP Address: ");
  Serial.println( WiFi.localIP() );  
}

Making the request:

  • Outside of loop() or setup(), initialize of the HttpClient:
    HttpClient client = HttpClient(wifi, serverAddress, 80);
  • Then, read Hall sensor value and send it with HTTP GET with:
    • Show Code
int sensorValue = 0;

void loop() {
  sensorValue = hallRead(); // or replace with averaged value code from above
  Serial.println("Sending sensor value: " + String(sensorValue));

  String url = "/update";
  url += "?api_key=" + String(apikey);
  url += "&field1=" + String(sensorValue);

  client.get(url); // perform the GET request

  // read the status code and body of the response
  int statusCode = client.responseStatusCode();
  String response = client.responseBody();

  Serial.print("Status code: ");
  Serial.println(statusCode);
  Serial.print("Response: ");
  Serial.println(response);
  Serial.println("Wait 15 seconds");
  delay(15000);
}

If your ESP32 is successfully sending data, you should be able to see it in the visualization plot on ThingSpeak.

Part 2 - calculating aggregate statistics with MatLab.

An important feature of ThingSpeak is the capability of running MatLab Analysis. You can set up code which performs processing and/or decison-making and then writes new data to a channel or notifies an external web service. Some examples of what you could do:

  • Combine data from multiple sources: your channel, other people's public channels and even external web services, do analysis based on tehm.
    • E.g. combine home air quality & heating data with a weather service and electricity grid price rates.
  • If your end-device is sending sensor values as analog voltage values (as we have been doing with ESP32), convert it into a standard, human-interpretable value
    • E.g. converting the resistance read by Arduino from a thermistor into a value in Celsius.

The functions using which you can read/write to Channels in Thingspeak Matlab are:

  • thingSpeakRead( .. )
  • thingSpeakWrite( .. )

They support various parameters, such as whether to fetch data based on a time-window or number of measurements.

Let's create a simple average sensor value calculation. In Thingspeak web interface:

  1. Apps -> MATLAB Analysis. Create a new Analysis.
  2. Choose the example "Calculate and display average humidity".
    • Modify it, so instead of humidity, we use our field1- magnetic value
    • Instead of reading data for last 60 minutes, try to read last 10 values:
      'NumPoints',10 instead of 'NumMinutes', 60
    • Try to run the analysis, don't use thingSpeakWrite() for now. You should see the average value in the "Output" panel below. If you see any errors instead, try to fix them.
  • Create a 2nd channel, we will write the analysis results here. Add 3 fields to it - min, max, mean.
    • Add calculation of min and max.
    • Write the data to our new channel - study the documentation of ThingSpeakWrite. We need to provide which fields we want to update. For example, if we want to update fields 5-7, the code would look like below.
      • thingSpeakWrite(CHANNEL_ID,'Fields',[5,6,7],'Values',{2.3,'on','good'},'WriteKey','CHANNEL_API_KEY')
    • Adapt the code so that you write the min, max and mean to the 2nd channel.

Running the analysis periodically with TimeControl

  • Finally, to make the MatLab analysis run at a time interval, you have to create a TimeControl app (Apps -> TimeControl).
    • Create a recurring TimeControl which triggers the Matlab code every 5 minutes.

Part 3 - Sending commands to the ESP32

ThingSpeak has a module called TalkBack. Clients can add new commands to a (sorted) queue and end-devices can fetch new commands to execute from the queue with a polling mechanism. We will create commands to turn the ESP32 integrated LED on or off.

Executing a command via HTTP ( Doc ): This removes the item from the queue and returns its value.

REQUEST:
POST https://api.thingspeak.com/talkbacks/<<talkBackId>>/commands/execute
content-type: "application/x-www-form-urlencoded"
content body: api_key=<<my_talback_api_key>>
RESPONSE:
The text content of the command. Commands don't have a predefined structure, their content is just a string. So, a commands value could be "LIGHT1_ON" or "{ "light1":"on", "sensor_interval" : { "value" : "60", "unit" : "seconds"} , for example - it is up to the developer to design.
  • Note that the TalkBack key is different than the channel key we used before!

Create a new TalkBack module. This will produce another API key and TalkBack module ID.

Let's replace the Arduino loop() code so that instead of sending sensor values, we are polling for new commands. Let's define two commands: "TURN_ON" and "TURN_OFF", and make the ESP32 respectively turn the in-built blue LED on/off.

Add your API key and ID as constants. Also define the pin of the integrated LED:

 
unsigned long myTalkBackID = 12345;
const char* myTalkBackKey = "XXXXXX";
const int LED_BUILTIN = 2;
  • Modify the loop() code by replacing the request with:
    • Talkback Request Show Code
// Create the TalkBack URI
String tbURI = String("/talkbacks/") + String(myTalkBackID) + String("/commands/execute");
String contentType = "application/x-www-form-urlencoded";
String postData =  "api_key=" + String(myTalkBackKey);                      

client.post(tbURI, contentType, postData);
  • Now, check the response code and response value, whether it contains a command:
    • Show Code for TalkBack response handling
// Check the result
if (statusCode == 200) {
  Serial.println("Checking TalkBack queue for new commands..."); 

  if(response.length() != 0) {
    Serial.print("  Latest command from queue: ");
    Serial.println(response);

    if(response == "TURN_ON") {
	  digitalWrite(LED_BUILTIN, HIGH);  
    } if(response == "TURN_OFF") {
	  digitalWrite(LED_BUILTIN, LOW);
    }

  } else {
    Serial.println("  No new commands.");  
  }

} else {
  Serial.println("Problem checking queue. HTTP status code " + String(statusCode));
}

Test it out by manually adding new commands from the TalkBack web app.

Part 4 - Feedback loop - sending data & reacting to it.

Now, let's update the ESP32 to both send data and listen for new commands. Secondly, we want ThingSpeak to automatically add a new command if the sensor values are below a threshold.

First, let's write the Arduino code. We could make two separate requests (one for writing data, one for fetching new commands). But ThingSpeak API also supports a request to do both at once.

Writing data and get commands via HTTP POST ( Doc ):

REQUEST:
POST https://https://api.thingspeak.com/update
content-type: "application/x-www-form-urlencoded"
content body: api_key=<<my_thingspeak_api_key>>&talkback_key=<<my_talkback_api_key>>&field1=<<some_value>>&field2=<<some_value>>&...
RESPONSE:
command string of the next TalkBack command in queue. If the update fails, the response is 0.
  • Try to update the POST request from part 3 so that it uses the above combined POST request instead and also sends the hall sensor value.

Data-based triggers in ThingSpeak with React

To complete the loop, let's make Thingspeak react on the data we are sending. We want a new command to be added to the TalkBack queue automatically, if the sensor value is above a certain limit.

We will use additional apps from ThingSpeak to achieve this:

  1. React - set up some rules on data values (e.g. a treshold) which trigger some behaviour (e.g. send a tweet)
  2. ThingHTTP - an app for defining HTTP requests that ThingSpeak can perform. A ThingHTTP request can be invoked by React or TimeControl.

React has the limitation - it can't directly add new TalkBack commands. However, what it can do is invoke ThingHTTP.

Meanwhile, the TalkBack REST API supports adding new commands via HTTP. So, we can define a ThingHTTP request which creates a new TalkBack Command. Then, we can set up a React rule to invoke that ThingHTTP request based on our data.

The flow will be:

ESP32 -> ThingSpeak Channel -> React -> ThingHTTP -> TalkBack API -> ESP32

Note: it's also possible to make HTTP requests from ThingSpeak Matlab code using webwrite.

  • Create a new ThingHTTP module which invokes the TalkBack API:

Adding a TalkBack command via HTTP POST ( Doc ):

REQUEST:
POST https://api.thingspeak.com/talkbacks/<talkback_id>/commands
content-type: "application/x-www-form-urlencoded"
content body: api_key=<<my_talkback_key>>&command_string=LIGHT_ON
RESPONSE:
-
  • Create a React module, which triggers the ThingHTTP if the hall sensor value exceeds some limit (based on the values you have been getting from the sensor), e.g when it is below 0.
    • For condition type use "Numeric"

Verify that the loop works.

Other information

There is also an Arduino ESP32/ESP8266 Thingspeak Library, if you prefer to avoid writing the HTTP requests yourself as we did in this lab.

  • Institute of Computer Science
  • Faculty of Science and Technology
  • University of Tartu
In case of technical problems or questions write to:

Contact the course organizers with the organizational and course content questions.
The proprietary copyrights of educational materials belong to the University of Tartu. The use of educational materials is permitted for the purposes and under the conditions provided for in the copyright law for the free use of a work. When using educational materials, the user is obligated to give credit to the author of the educational materials.
The use of educational materials for other purposes is allowed only with the prior written consent of the University of Tartu.
Terms of use for the Courses environment