Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
|
I've been working to learn more about the Arduino MKR GSM 1400 for a while and this is my attempt to set up a sketch that will publish data to the Thingspeak API in JSON format.
The sketch can be extended to monitor anything you like really. In its default format as presented, it will write sensor data and your location (latitude and longitude, as well as altitude and the accuracy of your location) through to a ThingSpeak channel.
This sketch was built from the basic GPRS SSL sketch by adding additional items and output to the serial monitor output such as the current phone network signal strength, etc.
It takes that basic sketch further by adding the Arduino JSON library and feeding the sensor and location data into a JSON array/object, which can be published directly to ThingSpeak.
Once connected, it will attempt to read the result of the connection to confirm it has successfully read or written to ThingSpeak via an HTTP status code, i.e. 200 or 202 (accepted).
In the second Iteration, it will publish the previous result code and the number of times the button has been pressed since the Arduino MKR GSM 1400 was powered on...
You may wish to eliminate the button altogether and just make it loop around every few seconds, so that if you did place the unit inside your fridge, you'd instantly know via your thingspeak graphs that the fridge light went out :)
Enjoy
To use this project:
1. Download the code.
2. Set up your project as shown in the Fritzing diagram.
3. Set up an account with ThingSpeak.
4. Modify the arduino_secrets.h file with your channel ID, and write API key as a minimum.
5. Compile the code and upload it to your MKR GSM 1400.
6. Monitor the output via serial.
7. Press the button.
8. Log in to the ThingSpeak website and look at your channel data to see if it changed.
mkr_gsm_1400_JSON-Thingspeak.ino
Arduino/*
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#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"
Comments