Introduction: BharatPi 4G HTTP POST to ThingSpeak - a Practical Guide

About: Bharat Pi is an IoT prototyping platform for students, innovators, startups and developers. A simplified board with an all in one compute network and storage on a single board to build rapid prototypes, colleg…

ThingSpeak is an Internet of Things (IoT) platform that allows you to collect, analyze, and visualize data from sensors or devices. It provides an easy-to-use interface for users to send data from their IoT devices to ThingSpeak servers using various communication protocols such as HTTP, MQTT, and ThingSpeak API. Once the data is in ThingSpeak, users can perform real-time analytics, create visualizations such as charts and maps, and trigger actions based on predefined conditions. ThingSpeak is often used in various IoT applications including environmental monitoring, home automation, and industrial automation.

Supplies

Sensor

Bharat Pi Boards

https://bharatpi.net/

ThingSpeak

https://thingspeak.com/

Arduino ide

Step 1: How to Create a Account in Thingspeak

Visit ThingSpeak: Go to the ThingSpeak website at [ThingSpeak thingspeak.com].

Click on Sign Up: In the top right corner of the homepage, you'll see a button labeled "Sign Up." Click on that button.

Fill out the Registration Form: On the registration page, you'll be asked to provide the following information:

  • Username: Choose a unique username that you'll use to log in to your ThingSpeak account.
  • Email Address: Enter a valid email address that you want to associate with your ThingSpeak account.
  • Password: Create a strong password that includes a combination of letters, numbers, and special characters. Make sure it's something you can remember easily but difficult for others to guess.
  • Confirm Password: Retype your chosen password to ensure there are no typos.

Create Account: Once you've filled out the form, click on the button that says "Create Account."

Verify Your Email (Optional): ThingSpeak might send a verification email to the address you provided. Check your inbox and follow any instructions in the email to verify your account.

Step 2: How to Create a Channel

Log in to ThingSpeak: Go to the ThingSpeak website ([ThingSpeak thingspeak.com]) and enter your login credentials.

Access Channels: Once logged in, navigate to the "Channels" section. You can usually find this by clicking on the "Channels" tab or a similar option on the ThingSpeak dashboard.

Create New Channel: Look for a button labeled "New Channel" or "Create Channel." Clicking on this button will initiate the channel creation process.

Channel Settings: Here, you'll define the specifics of your channel:

  • Name: Choose a descriptive name for your channel that reflects the type of data it will store (e.g., "Home Temperature Monitoring").
  • Fields: Select the number of data fields you want your channel to have (usually 1 to 8). Each field will represent a specific sensor measurement you plan to collect.
  • You can check the boxes next to "Field 1" to "Field 8" depending on how many data streams you need.
  • ThingSpeak allows you to name each field later, making it easier to understand what data is being stored in each slot.

Public View (Optional): By default, channels are private. You can choose to make your channel public if you want to share the data with others.

Save Channel: Once you've filled out the channel settings, click on the "Save Channel" button.

Step 3: Arduino Ide

code is written in Arduino IDE for the Bharat Pi 4G board. It aims to connect to the internet using a 4G SIM card and send sensor data to a ThingSpeak cloud platform.

 Library inclusions:

  • TinyGsmClient.h: This library enables communication with the 4G module using AT commands.
  • SPI.h: This library provides functions for Serial Peripheral Interface (SPI) communication, which might be used for the 4G module.
  • ArduinoJson.h: This library helps with parsing and creating JSON data formats.
  • Ticker.h: This library might be used for scheduling tasks or timers.

2. Configuration:

  • TINY_GSM_MODEM_SIM7600: This line defines the 4G modem model being used (SIM7600).
  • APN: This variable stores the Access Point Name (APN) of your network provider, which is crucial for internet connectivity. You'll need to replace "airtelgprs.com" with the appropriate APN for your SIM card.
  • cloud_url: This variable holds the ThingSpeak update URL for sending data as a JSON object.
  • apiKey: This variable stores your unique ThingSpeak API key, which is required for authentication. Replace "VJP11NDRLY1BGODD" with your actual key.

3. Modem Functions:

  • modemPowerOn(), modemPowerOff(), and modemRestart(): These functions manage the power state of the 4G modem.
  • modemInit(): This function initializes the communication with the 4G module.

4. Setup:

  • Serial communication is established for the Arduino console and the 4G module.
  • The code checks for modem initialization and retrieves basic information like the modem name and information.
  • It attempts to connect to the cellular network using different network modes (automatic, GSM only, LTE only, or GSM and LTE) until successful. Signal quality and network operator details are printed during the process.

5. Sending Data to ThingSpeak:

  • Dummy temperature values are assigned to variables temperature1 and temperature2. In a real scenario, you would replace these with sensor readings or data from your application.
  • A JSON object payloadObj is created, containing the API key and the sensor data (temperature1 and temperature2).
  • The code establishes an HTTP connection with the ThingSpeak cloud URL and sets the content type as "application/json".
  • It sends the JSON data (payload) to the ThingSpeak server using an HTTP POST request.
  • Finally, the HTTP connection is terminated.

6. Loop:

  • This section is currently commented out. It might be intended for continuously capturing data from sensors or GPIOs and sending it to ThingSpeak in a loop. You'll need to uncomment this section and replace the placeholder with your sensor data reading logic.

GSM CODE

/*************************************************************************
   PROJECT: Bharat Pi 4G Board Sample Code for data push to Thingspeak Cloud
   AUTHOR: Bharat Pi

   FUNC: 4G testing with HTTP call to Thingspeak cloud server.

   SIMCARD: 4G sim cards from Airtel/Vodaphone/Jio/BSNL can be used.
            To test HTTP request ensure you have data plan.

   IMPORTANT: Configure the APN accordingly as per your Sim provider

   GPS: If you have bought Bharat Pi wtih GPS board then you need to connect
        the GPS antenna to the UFL connector and antenna should have clear sky visibility
        preferrably on the terrace or open field.


   TODO: (Before you upload the code to Bharat Pi board)
   1) Change APN as per your Sim provider
   2) Change the Thingspeak API key as per your account/setup
   3) Use a power adapter 9V 2amps as the 4G module requires enough power to operate

   DESC: This script will connect using 4G sim and makes a http call
   to a Thingspeak cloud server setup as per your Thingspeak API key.

   COPYRIGHT: BharatPi @MIT license for usage on Bharat Pi boards
 *************************************************************************/


#define TINY_GSM_MODEM_SIM7600 //TINY_GSM_MODEM compatible for 7672 as well
#define TINY_GSM_RX_BUFFER 1024


#define SerialAT Serial1
#define SerialMon Serial


#define UART_BAUD   115200
#define PIN_DTR     25
#define PIN_TX      17
#define PIN_RX      16
#define PWR_PIN     32


#define LED_PIN 2


#include <TinyGsmClient.h>
#include <SPI.h>
#include <ArduinoJson.h>
#include <Ticker.h>


/*********************************************
  SECTION: Set APN based on your sim card
    AIRTEL: "airtelgprs.com"
    BSNL: "bsnlnet"
    VI: "portalnmms"
    JIO: "jionet"
*********************************************/
const char apn[]  = "airtelgprs.com"; //Change this as per your Sim card operator


/*********************************************
  SECTION: Set Thingspeak cloud and respective API key
*********************************************/
String cloud_url = "https://api.thingspeak.com/update.json"; //Thingspeak update URL for sending data as JSON object
String apiKey = "VJP11NDRLY1BGODD";  // change this to the thingspeak API key as per your account

StaticJsonDocument<200> payloadObj; //for testing http request


#ifdef DUMP_AT_COMMANDS
  #include <StreamDebugger.h>
  StreamDebugger debugger(SerialAT, SerialMon);
  TinyGsm modem(debugger);
#else
  TinyGsm modem(SerialAT);
#endif


/*********************************************
  SECTION: Modem operation functions
*********************************************/
void modemPowerOn(){
  pinMode(PWR_PIN, OUTPUT);
  digitalWrite(PWR_PIN, LOW);
  delay(1000);
  digitalWrite(PWR_PIN, HIGH);
}


void modemPowerOff(){
  pinMode(PWR_PIN, OUTPUT);
  digitalWrite(PWR_PIN, LOW);
  delay(1500);
  digitalWrite(PWR_PIN, HIGH);
}


void modemRestart(){
  modemPowerOff();
  delay(1000);
  modemPowerOn();
}


/*********************************************
  SECTION: Main setup
*********************************************/
void setup(){
  // Set console baud rate
  SerialMon.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);


  delay(100);


  modemPowerOn();
  SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX);
  Serial.clearWriteError();
  Serial.println();
  Serial.println();
  Serial.println("/**********************************************************/");
  Serial.println("  Bharat Pi 4G/LTE Board Test Program");
  Serial.println("  To initialize the network test, please make sure the antenna has been");
  Serial.println("  connected and SIM card is inserted in the SIM slot (back side of the board).");
  Serial.println("/**********************************************************/\n\n");


  delay(5000);


  String res;
  Serial.println("Initializing Modem...");


  if (!modem.init()) {
    digitalWrite(LED_PIN, HIGH);
    modemRestart();
    delay(2000);
    Serial.println("Failed to restart modem, continue without restarting");
    digitalWrite(LED_PIN, LOW);
    return;
  }


  //Blue LED on the board use as an indicator
  //If blinking: Modem not able to boot
  //If turned ON: connected to network
  //If turned OFF: Modem booted successfully but not connected to network, check your SIM, network coverage etc.


  digitalWrite(LED_PIN, LOW);


  Serial.println("Running SIMCOMATI command...");
  modem.sendAT("+SIMCOMATI"); //Get the module information
  modem.waitResponse(1000L, res);
  res.replace(GSM_NL "OK" GSM_NL, "");
  Serial.println(res);
  res = "";
  Serial.println();


  Serial.println("Preferred mode selection (GSM/LTE)...");
  modem.sendAT("+CNMP?");
  if (modem.waitResponse(1000L, res) == 1) {
    res.replace(GSM_NL "OK" GSM_NL, "");
    Serial.println(res);
  }
  res = "";
  Serial.println();


  //This section is only applicable for testing modules with NBIoT,
  //for other modules the command doesnt return anything and can be ignored while testing
  Serial.println("Preferred selection between CAT-M and NB-IoT...");
  modem.sendAT("+CMNB?");
  if (modem.waitResponse(1000L, res) == 1) {
    res.replace(GSM_NL "OK" GSM_NL, "");
    Serial.println(res);
  }
  res = "";
  Serial.println();


  //Get module manufacturer details
  String modemName = modem.getModemName();
  Serial.println("Modem Name : " + modemName);
  delay(1000);


  String modemInfo = modem.getModemInfo();
  Serial.println("Modem Info : " + modemInfo);
  delay(1000);


  /*********************************************
    SECTION: Connect to Sim network
  *********************************************/
  Serial.println("Network mode connectivity testing (GSM, LTE or GSM/LTE)...");


  for (int i = 0; i <= 4; i++) {
    uint8_t network[] = {
        2,  /*Automatic*/
        13, /*GSM only*/
        38, /*LTE only*/
        51  /*GSM and LTE only*/
    };
    Serial.printf("Try %d method\n", network[i]);
    modem.setNetworkMode(network[i]);
    delay(3000);
    bool isConnected = false;
    int tryCount = 60;
    while (tryCount--) {
      String netoworkOerator = modem.getOperator();
      Serial.print("Operator: ");
      Serial.println(netoworkOerator);
      int16_t signal =  modem.getSignalQuality();
      Serial.print("Signal: ");
      Serial.println(signal);
      Serial.print("isNetworkConnected: ");
      isConnected = modem.isNetworkConnected();
      Serial.println( isConnected ? "CONNECTED" : "NOT CONNECTED YET");
      if (isConnected) {
        break;
      }
      delay(1000);
      digitalWrite(LED_PIN, !digitalRead(LED_PIN));
    }
    if (isConnected) {
        break;
    }
  }
  digitalWrite(LED_PIN, HIGH); //Modem connected to network


  Serial.println();
  Serial.println("Yehhh....Device is connected to Sim network.");
  Serial.println();


  delay(1000);
  Serial.println("Checking UE (User Equipment) system information...");
  Serial.println();
  modem.sendAT("+CPSI?");
  if (modem.waitResponse(1000L, res) == 1) {
    res.replace(GSM_NL "OK" GSM_NL, "");
    Serial.println(res);
  }


  delay(1000);  
  Serial.println("");
  Serial.println("");  


  delay(2000);


  /******************************************************************
  SECTION: Set dummpy variable for pushing data to cloud.
           If you want to dynamically capture data from
           sensors or GPIOs then move this section to Loop
           and set variables accordingly to push data to Thingspeak.
  *******************************************************************/
  String payload;
  double temperature1 = 56.9; //Dummy vairable to send temperature
  double temperature2 = 23.9; //Dummy vairable to send temperature


  payloadObj["api_key"] = apiKey;
  payloadObj["field1"] = temperature1;
  payloadObj["field2"] = temperature2;


  serializeJson(payloadObj, payload); //Convert data to json format


  Serial.print("Paylod length: ");
  Serial.println(payload.length());  


  Serial.println();
  Serial.println(">>>>> Begin Thingspeak Cloud Sync <<<<<<");
  Serial.println();
  Serial.println("NOTE: Please ensure to have a Thingspeak account and API is setup.");
  Serial.println("Thingspeak URL: " + cloud_url);
  Serial.println("Thingspeak API Key: " + apiKey);
  Serial.println();
  Serial.println();
  delay(2000);


  Serial.println("Initiating HTTP call to Thingspeak");
  modem.sendAT("+HTTPINIT"); //init HTTP
  if (modem.waitResponse(10000L) != 1) {
    Serial.println("ERROR: HTTP INIT FAILED!");
    DBG("+HTTPINIT");
  }
  delay(5000);


  /******************************************************************
  SECTION: Make an API call to Thingspeak server with sensor data as a Json object
  *******************************************************************/  


  modem.sendAT("+HTTPPARA=\"URL\"," + cloud_url); //set call back URL to test
  if (modem.waitResponse(10000L) != 1) {
    Serial.println("ERROR: HTTP URL SETTING FAILED!");
    DBG("+HTTPPARA=\"URL\"," + cloud_url);
  }


  modem.sendAT("+HTTPPARA=\"CONTENT\",\"application/json\"");   //For test purpose we are sending plain text data. If sending json data then replace: text/plain -> application/json
  if (modem.waitResponse(10000L) != 1) {
    Serial.println("ERROR: HTTP CONTENT TYPE SETTING FAILED");
    DBG("+HTTPPARA=\"CONTENT\",\"application/json\"");
  }
  modem.sendAT("+HTTPDATA=" + String(payload.length()) + ",20000"); //length of the body (data) and max time required in milliseconds to input the data
  //HTTPDATA responds with DOWNLOAD so need to wait for this and then send the body/data of the post call
  while (modem.waitResponse(1000UL, "DOWNLOAD") != 1) {
      Serial.print(".");
  }
  delay(2000);


  //Send the body/data of the post call
  //JSON payload or it can even be a plain text. Read the Thingspeak API reference manual. https://in.mathworks.com/help/thingspeak/rest-api.html
  modem.streamWrite(payload);
  if (modem.waitResponse(10000L) != 1) {
    Serial.println("ERROR: SENDING POST DATA");
  }
  delay(2000);

  Serial.println("Executing HTTP POST call");
  modem.sendAT("+HTTPACTION=1"); //Execute post
  if (modem.waitResponse(10000UL) != 1) {
    Serial.println("ERROR: HTTP POST CALL FAILED!");
    DBG("+HTTPACTION=1");
  } else {
    Serial.print("Data sent to API: ");
    Serial.println(payload);    
    Serial.print("Post call response:");
    modem.sendAT("+HTTPREAD");
    if(modem.waitResponse(60000L) !=1 ){
      DBG(GF("+HTTPREAD"));
    }
    delay(2000);
    modem.sendAT("+HTTPHEAD");
    delay(2000);
    Serial.println();
    Serial.println("Terminating HTTP");
    modem.sendAT("+HTTPTERM");
    delay(2000);
  }


  Serial.println(">>>>> END OF Thingspeak Cloud Sync <<<<<<");
}


/******************************************************************
SECTION: Loop call for capturing synamic data from sensors/GPIOs
*******************************************************************/  


void loop(){
  //Print data to Arduino serial monitor
  while (1) {
    while (SerialAT.available()) {
      SerialMon.write(SerialAT.read());
    }
    while (SerialMon.available()) {
      SerialAT.write(SerialMon.read());
    }
  }    
}


Step 4: Wifi Code

#include <WiFi.h>
#include "DHT.h"


// WiFi credentials
const char* ssid = "smile123";
const char* password = "123456789";


// Thingspeak API key
const String apiKey = "20MNHFQKV1NFW83I";


// Thingspeak server
const char* server = "api.thingspeak.com";


// DHT sensor pin and type
#define DHTPIN 23
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);


void setup() {
  Serial.begin(115200);
  Serial.println("Serial Begin");


  // Initialize DHT sensor
  dht.begin();

  // Connect to WiFi
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
}


void loop() {
  // Read DHT sensor data
  float humidity = dht.readHumidity();
  float temperature = dht.readTemperature();

  // Check if any reads failed and exit early (to try again)
  if (isnan(humidity) || isnan(temperature)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }


  // Send data to Thingspeak
  if (sendToThingspeak(humidity, temperature)) {
    Serial.println("Data sent to Thingspeak successfully");
  } else {
    Serial.println("Failed to send data to Thingspeak");
  }

  // Delay before next reading
  delay(10000); // Delay for 10 seconds (adjust as needed)
}


bool sendToThingspeak(float humidity, float temperature) {
  WiFiClient client;


  // Create HTTP request body
  String requestBody = "api_key=" + apiKey;
  requestBody += "&field1=" + String(humidity);
  requestBody += "&field2=" + String(temperature);

  // Send HTTP POST request to Thingspeak
  if (client.connect(server, 80)) {
    client.println("POST /update HTTP/1.1");
    client.println("Host: api.thingspeak.com");
    client.println("Connection: close");
    client.println("Content-Type: application/x-www-form-urlencoded");
    client.println("Content-Length: " + String(requestBody.length()));
    client.println();
    client.print(requestBody);
    delay(500); // Allow time for response
    client.stop();
    return true; // Data sent successfully
  } else {
    Serial.println("Connection to Thingspeak failed");
    return false; // Failed to send data
  }
}
  1. Include necessary libraries:
  • WiFi.h: Library for connecting to Wi-Fi networks.
  • DHT.h: Library for interfacing with DHT temperature and humidity sensors.
  1. Define Wi-Fi credentials (ssid and password) and ThingSpeak API key (apiKey).
  2. Define the ThingSpeak server address (server) and specify the DHT sensor pin and type.
  3. In the setup() function:
  • Initialize serial communication for debugging.
  • Initialize the DHT sensor.
  • Connect to the Wi-Fi network.
  1. In the loop() function:
  • Read temperature and humidity data from the DHT sensor.
  • Check if the sensor readings are valid.
  • Send the data to ThingSpeak using the sendToThingspeak() function.
  • Delay for a specified time before taking the next reading.
  1. The sendToThingspeak() function:
  • Creates an HTTP POST request body with the API key and sensor data.
  • Establishes a connection to the ThingSpeak server.
  • Sends the HTTP POST request with the data.
  • Checks if the connection to ThingSpeak was successful and returns a boolean value accordingly.


Step 5: ThingSpeak