smgs
Published © GPL3+

MKR GSM 1400 Send Sensor Data to ThingSpeak via JSON

Write basic sensor data to ThingSpeak via JSON, extended to also write latitude and longitude and store it on ThingSpeak upon button press.

IntermediateFull instructions provided1 hour910
MKR GSM 1400 Send Sensor Data to ThingSpeak via JSON

Things used in this project

Hardware components

Grove - Digital Light Sensor
Seeed Grove - Digital Light Sensor
×1
LED (generic)
LED (generic)
×1
Breadboard (generic)
Breadboard (generic)
×1
Arduino MKR GSM 1400
Arduino MKR GSM 1400
×1
Resistor 10k ohm
Resistor 10k ohm
×1
Resistor 221 ohm
Resistor 221 ohm
×1

Software apps and online services

ThingSpeak API
ThingSpeak API

Story

Read more

Schematics

MKR GSM 1400 sends light sensor data to Thingspeak via JSON

fitzring diagram
Mkr gsm 1400 talking to thingspeak bb 1agjfm0erq

Code

mkr_gsm_1400_JSON-Thingspeak.ino

Arduino
Send light sensor data through to Thingspeak, needs arduino_secrets.h as well...
/*
  Web client

 This sketch connects to the Thingspeak website using SSL through a MKR GSM 1400 board. Specifically,
 this example performs a write operation to the thingspeak channel specified in the
 arduino_secrets.h file.
 
 It only performs a write GPRS connection through to Thingspeak when the button is depressed.
 
 You can Change the fields it writes to on Thingspeak as you wish This sketch also prints output to the Serial monitor
 to let you know where it is up to at any given time, lagrely for debugging.

 Other Stuff:
 optional stuff added this sketch currently is the ability to turn an LED on, based on the results of reading a Thingspeak field value.
 A light sensor so that we can read the light value and add that to a Thingspeak field in near realtime and track the lgith throughout the day.

 If the code and the comments disagree, then both are probably wrong. -- Norm Schryer

  Changes:
  04092018 - Added inital code and used the ArduinoJSON libraries
  05092018 - updated serial speed from Max of 115200 to something more stable, 57600
  07092018 - heavily updated JSON formatting code
  17092018 - Added watchdog function in case of HTTP post failure
  18092018 - Tested working with writing Lat and Long through to ThingSpeak 
           - Added functions to print a better status output to Thingspeak status field
           - Made the secret channel id go through properly, pulls in directly from the arduino_secrets.h file where it is defined...
           

 Circuit:
 * MKR GSM 1400 board
 * Antenna
 * SIM card with a data plan
 * Push Button
 * LED
 * Resistor
 * TEMT 600 Light Sensor
 * Breadboard

 created 05 Feb 2018
 by SMGS
*/

#include <MKRGSM.h>
#include "arduino_secrets.h" 
#include <ArduinoJson.h>
#include <Adafruit_SleepyDog.h>

// Please enter your sensitive data in the Secret tab or arduino_secrets.h
// PIN Number
const char PINNUMBER[]     = SECRET_PINNUMBER;
// APN data
const char GPRS_APN[]      = SECRET_GPRS_APN;
const char GPRS_LOGIN[]    = SECRET_GPRS_LOGIN;
const char GPRS_PASSWORD[] = SECRET_GPRS_PASSWORD;

// Thingspeak Secret Settings
//char writeAPIKey[]      = secretWriteAPIKey;
//char readAPIKey[]       = secretReadAPIKey;
//char channelID[]        = secretChannelID;

// initialize the library instance
GSMSSLClient client;
GSM gsmAccess;
GPRS gprs;
GSMLocation location;
GSMScanner scanner;

// Domain name and port that we will connect too (for example: api.thingspeak.com)
char server[] = "api.thingspeak.com";
int port = 443; // port 443 is the default for HTTPS

int lightLevel; //setup the Light Level field for us to store the current result in from the TEMT6000 Sensor 
float t_latitude;
float t_longitude;
long t_altitude;
long t_accuracy;

// The constants won't change. They're used here to set Arduino pin numbers:
const int buttonPin = 6;      // the number of the pushbutton pin
const int ledPin =  13;       // the number of the LED pin
int buttonState = LOW;        // Initialised variable for reading the pushbutton status
String stat;        // Used to capture the Previous runs response code
String cResp = "First run";
long buttonIterations = 0;    //Track the number of runs since last bootup.


// Memory pool for JSON object tree.
//
// Inside the brackets, 200 is the size of the pool in bytes.
// Don't forget to change this value to match your JSON document.
// Use arduinojson.org/assistant to compute the capacity.
StaticJsonBuffer<200> jsonBuffer;

void setup() {
  
  // put your setup code here, to run once:
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);

  // initialize serial communications and wait for port to open:
  Serial.begin(57600); //Using a conservative Baud rate (max is 115200)
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  
  Serial.println("Starting Arduino web client.");
  // connection state
  boolean connected = false;

  // Connect to the cellular Network
  // After starting the modem with GSM.begin()
  // attach the shield to the GPRS network with the APN, login and password
  while (!connected) 
  {
    if ((gsmAccess.begin(PINNUMBER) == GSM_READY) &&
        (gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY)) 
    {
      connected = true;
    } 
    else 
    {
      Serial.println("Not connected");
      delay(1000);
    }
  }
  location.begin();
  delay(1000); //Give the Location thingy time to startup
  
  Watchdog.enable(10000); //Start a 10 second watchdog timer
}

void loop() {
  // put your main code here, to run repeatedly:
  lightLevel = analogRead(A2); //read the current light level value and store it
  buttonState = digitalRead(buttonPin); // read the state of the pushbutton value:
  // check if the pushbutton is pressed. If it is, the buttonState is HIGH:
  digitalWrite(ledPin, LOW);  // turn LED OFF Unless the button gets pressed
  if (buttonState == HIGH) 
  {
    // Reset the watchdog with every loop to make sure the sketch keeps running.
    // If you comment out this call watch what happens after about 4 iterations!
    Watchdog.reset();
    
    digitalWrite(ledPin, HIGH);  // turn LED on to indicate button has been depressed and things are in progress:

    stat = ("Arduino MKR GSM 1400 - run number: ");
    stat += (buttonIterations);
    stat += (" Response code: ");
    stat += (cResp); //Store the response to send through as the status on the next run
    buttonIterations++; //Add one button press for the next Iteration.
    String sigStrength = scanner.getSignalStrength();

    // Run Function to get the current Location of the device from the Network
    // This needs to run a few times before it becomes accurate
    getLocation();
    
    Serial.println(F("Connecting to HTTP Server..."));

    // Connect to HTTP server
    if (!client.connect(server, port)) {
      Serial.println(F("Connection failed"));
      return;
    }
    Serial.println(F("Connected!"));
    
    // Create the JSON Array and the root of the object tree.
    //
    // It's a reference to the JsonObject, the actual bytes are inside the
    // JsonBuffer with all the other nodes of the object tree.
    // Memory is freed when jsonBuffer goes out of scope.
    const size_t bufferSize = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(10);
    DynamicJsonBuffer jsonBuffer(bufferSize);
    JsonObject& root = jsonBuffer.createObject();
    root["write_api_key"] = secretWriteAPIKey;
    JsonArray& updates = root.createNestedArray("updates");
    JsonObject& updates_0 = updates.createNestedObject();
    updates_0["delta_t"] = 0;   //Currently using Delta_T rather than a realtime clock because it's easier...
    updates_0["field1"] = lightLevel; // Light Level from TEMT6000 Sensor
    updates_0["field2"] = t_accuracy; // Location Accuracy
    updates_0["field3"] = sigStrength; // Phone Signal Strength
    //updates_0["field4"] = "4";
    //updates_0["field5"] = "5";
    //updates_0["field6"] = 600;
    //updates_0["field7"] = 700;
    //updates_0["field8"] = 800;
    updates_0["latitude"] = t_latitude; // Location Latitude
    updates_0["longitude"] = t_longitude; // Location Longitude
    updates_0["elevation"] = t_altitude; // Location Altitude/Elevation
    updates_0["status"] = stat; // Total Button Presses/Runs + The previous response code
    
    //root.printTo(Serial);
    //Serial.println();
    //root.prettyPrintTo(Serial);

    Serial.println("connected to: ");
    Serial.println(server);
    Serial.println(port);
    Serial.println("Beginnning JSON Post Sequence");
    Serial.println();
    client.print("POST /channels/");
    client.print(secretChannelID);
    client.println("/bulk_update.json HTTP/1.1");
    Serial.print("POST /channels/");
    Serial.print(secretChannelID);
    Serial.println("/bulk_update.json HTTP/1.1");
    client.println("Host: api.thingspeak.com");
    Serial.println("Host: api.thingspeak.com");
    client.println("User-Agent: mw.doc.bulk-update (Arduino MKR GSM 1400)");
    Serial.println("User-Agent: mw.doc.bulk-update (Arduino MKR GSM 1400)");
    client.println("Connection: close");
    Serial.println("Connection: close");
    client.println("Content-Type: application/json");
    Serial.println("Content-Type: application/json");
    client.print("Content-Length: ");
    Serial.print("Content-Length: ");
    client.println(root.measurePrettyLength());
    Serial.println(root.measurePrettyLength());
    
    // Terminate headers
    client.println();
    Serial.println();

    // Send body
    root.prettyPrintTo(client);
    root.prettyPrintTo(Serial);

    delay(350); //Wait to receive the response
    client.parseFloat();
    cResp = String(client.parseInt());
    Serial.println();
    Serial.println("Response code: "+cResp); // Print the response code. 202 indicates that the server has accepted the response
    stat = ("Arduino MKR GSM 1400 - run number: ");
    stat += (buttonIterations);
    stat += (" Response code: ");
    stat += (cResp); //Store the response to send through as the status on the next run
    
    // Disconnect
    client.stop();


  } //End of Button Being Pressed Thingy
  
  // Reset the watchdog with every loop to make sure the sketch keeps running.
  Watchdog.reset();
    
} //End of Loop

void getLocation()
{
  if (location.available())
  {
    int counter = 0;
    boolean locationTest = true;
    long locationMax = 3738000; //Max is usually 3738000
    long locationAccuracy;
    long laRef = 38000; //38 kilometers
    
    while(location.accuracy() == 3738000) 
    {
      // Reset the watchdog with every loop to make sure the sketch keeps running.
      // If you comment out this call watch what happens after about 4 iterations!
      Watchdog.reset();
      location.latitude();
      location.longitude();
      location.altitude();
      location.accuracy();

      delay(2000); //wait a bit then have another look see
    }

    // This is probably redundant but it may work better than the one above...
    while (locationTest == true && counter < 50) 
    {
      // Reset the watchdog with every loop to make sure the sketch keeps running.
      // If you comment out this call watch what happens after about 4 iterations!
      Watchdog.reset();
      
      location.latitude();
      location.longitude();
      location.altitude();
      location.accuracy();
      locationAccuracy = location.accuracy();
            
      if (locationAccuracy < laRef ) //38 kilometers, i.e. it's in the same city as the ballpark...
      {
        Serial.println("Location is currently precise to within ");
        Serial.print(locationAccuracy);
        Serial.print("m");
        Serial.println("Location: ");
        Serial.print(location.latitude(), 7);
        Serial.print(", ");
        Serial.println(location.longitude(), 7);
      
        Serial.print("Altitude: ");
        Serial.print(location.altitude());
        Serial.println("m");
      
        Serial.print("Accuracy: +/- ");
        Serial.print(location.accuracy());
        Serial.println("m");
        Serial.println();
        
        t_latitude = location.latitude();
        t_longitude = location.longitude();
        t_altitude = location.altitude();
        t_accuracy = location.accuracy();
        locationTest = false;
        break; //exit the while loop
      }

      counter++;
      delay(1000);
    } 
  }
}

arduino_secrets.h

Arduino
Secret File where you store the SIM card PIN number, Thingspeak channel number etc
#define SECRET_PINNUMBER     "0123"
#define SECRET_GPRS_APN      "internet" // replace your GPRS APN
#define SECRET_GPRS_LOGIN    "login"    // replace with your GPRS login
#define SECRET_GPRS_PASSWORD "password" // replace with your GPRS password

// Thingspeak Settings
#define secretWriteAPIKey  "1234567890ABCDEFGH"
#define secretReadAPIKey  "1234567890ABCDEFGH"
#define secretChannelID   "999999"

Credits

smgs

smgs

1 project • 1 follower

Comments

Add projectSign up / Login