IoT DataLogger
Category: Local Data/Mapping
Components: GPS
Created By: Anonymous
Difficulty Level: Intermediate
Input Sensor: button
Microcontroller: NodeMCU
Output Device: Google Sheets
Prototyped by: @gautamp
Status: In Progress
Discover:
Mapping local issues is time consuming. If using a chatbot, you need to type keyword, select category, share location and then submit. If using a mapping tool, you need to login, and then locate yourself and fill in the same details. What if you could map issues with the press of a button (assumption - your device is connected to a wifi hotspot)
Investigation
Using the chatbot, we tried mapping, and this took about 1 minute, but users felt that it took 3 minutes to do the same. This button pressing action felt easier. Product Demo is below.
Solution (V1)
Component | Connected to pin on NodeMCU |
---|---|
GPS VCC | 3V3 |
GPS GND | GND |
GPS RX | D4 |
GPS TX | D3 |
Button leg 1 | 3V3 |
Button leg 2 | Via resistor (220 ohm) shorting ground and D1 |
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
#include <WiFiClientSecure.h>
/*
This sample sketch demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
It requires the use of SoftwareSerial, and assumes that you have a
4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx). Thank you Mikal for the library.
*/
static const int RXPin = 0, TXPin = 2; //change if you use different pins
static const uint32_t GPSBaud = 9600;
//Button
int button = 5;
//Device ID
String device = "gp001"; //Change this
String tim = "";
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
//Google Server Setup Section
const char* host = "script.google.com";
const int httpsPort = 443;
WiFiClientSecure client;
const char* fingerprint = "46 B2 C3 44 9C 59 09 8B 01 B6 F8 BD 4C FB 00 74 91 2F EF F6";
String GAS_ID = "AKfycbxtSVvRVh16mXK44mzzjaKJrWrNEdN-eOEmgaibG3ETyvAn_rP6-uaNgUU2mqZXgrsG"; // Replace by your Google App S service id
//Set up to send to GSheets
String readString;
void setup()
{
Serial.begin(115200);
ss.begin(GPSBaud);
pinMode(button, INPUT);
WiFiManager wifiManager;
wifiManager.setTimeout(180);
if (!wifiManager.autoConnect("SetupWIFIDataLogger")) {
Serial.println("failed to connect and hit timeout");
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);
}
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
delay(3000);
}
void loop()
{
// This sketch displays information every time a new sentence is correctly encoded.
while (ss.available() > 0)
if (gps.encode(ss.read())) {
// displayInfo();
int buttonpress = digitalRead (button);
if (buttonpress != 0) {
Serial.println("button pressed");
displayInfo();
}
}
if (millis() > 5000 && gps.charsProcessed() < 10)
{
Serial.println(F("No GPS detected: check wiring."));
while (true);
}
}
void displayInfo()
{
Serial.print(F("Location: "));
if (gps.location.isValid())
{
Serial.print(gps.location.lat(), 6);
Serial.print(F(","));
Serial.print(gps.location.lng(), 6);
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" Date/Time: "));
if (gps.date.isValid())
{
Serial.print(gps.date.month());
Serial.print(F("/"));
Serial.print(gps.date.day());
Serial.print(F("/"));
Serial.print(gps.date.year());
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" "));
if (gps.time.isValid())
{
if (gps.time.hour() < 10) Serial.print(F("0"));
Serial.print(gps.time.hour());
Serial.print(F(":"));
if (gps.time.minute() < 10) Serial.print(F("0"));
Serial.print(gps.time.minute());
Serial.print(F(":"));
if (gps.time.second() < 10) Serial.print(F("0"));
Serial.print(gps.time.second());
Serial.print(F("."));
if (gps.time.centisecond() < 10) Serial.print(F("0"));
Serial.print(gps.time.centisecond());
tim = "test";
}
else
{
Serial.print(F("INVALID"));
}
Serial.println();
senddata();
}
void senddata() {
client.setInsecure();
Serial.print("connecting to ");
Serial.println(host);
if (!client.connect(host, httpsPort)) {
Serial.println("connection failed");
return;
}
if (client.verify(fingerprint, host)) {
Serial.println("certificate matches");
} else {
Serial.println("certificate doesn't match");
}
String url = "/macros/s/" + GAS_ID + "/exec?device=" + device + "&lati=" + String(gps.location.lat(), 6) + "&longi=" + String(gps.location.lng(), 6) + "&time=" + tim;
Serial.print("requesting URL: ");
Serial.println(url);
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"User-Agent: BuildFailureDetectorESP8266\r\n" +
"Connection: close\r\n\r\n");
Serial.println("request sent");
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line == "\r") {
Serial.println("headers received");
break;
}
}
String line = client.readStringUntil('\n');
if (line.startsWith("{\"state\":\"success\"")) {
Serial.println("esp8266/Arduino CI successfull!");
} else {
Serial.println("esp8266/Arduino CI has failed");
}
Serial.println("reply was:");
Serial.println("==========");
Serial.println(line);
Serial.println("==========");
Serial.println("closing connection");
}
Server Side setup (if you want to keep your data with you only, and not share with commons)
- Create a google sheet and make it open to anyone to read
-
Create App, and paste this code in it -
- name script same name as google sheet
- copy google sheet ID and paste in “sheet_id”
- deploy, using your email ID, but usable by all and copy Google App Script ID and paste in Arduino Code under “GAS_ID”
function doGet(e) {
Logger.log( JSON.stringify(e) ); // view parameters
var result = 'Ok'; // assume success
if (e.parameter == 'undefined') {
result = 'No Parameters';
}
else {
var sheet_id = '1Qjt4O5MYtNIwlHFQ6k29tWzjXiUHS98LWcbdNwbuxzU'; // Spreadsheet ID
var sheet = SpreadsheetApp.openById(sheet_id).getActiveSheet(); // get Active sheet
var newRow = sheet.getLastRow() + 1;
var rowData = [];
rowData[0] = new Date(); // Timestamp in column A
for (var param in e.parameter) {
Logger.log('In for loop, param=' + param);
var value = stripQuotes(e.parameter[param]);
Logger.log(param + ':' + e.parameter[param]);
switch (param) {
case 'device': //Parameter
rowData[1] = value; //Value in column B
result = 'Written on column B';
break;
case 'lati': //Parameter
rowData[2] = value; //Value in column C
result += ' ,Written on column C';
break;
case 'longi': //Parameter
rowData[3] = value; //Value in column C
result += ' ,Written on column D';
break;
case 'time': //Parameter
rowData[4] = value; //Value in column C
result += ' ,Written on column E';
break;
default:
result = "unsupported parameter";
}
}
Logger.log(JSON.stringify(rowData));
// Write new row below
var newRange = sheet.getRange(newRow, 1, 1, rowData.length);
newRange.setValues([rowData]);
}
// Return result of operation
return ContentService.createTextOutput(result);
}
/**
* Remove leading and trailing single or double quotes
*/
function stripQuotes( value ) {
return value.replace(/^["']|['"]$/g, "");
}
Dashboard (embedded here)
https://datastudio.google.com/reporting/87818c3c-5ed4-424d-b4af-1fa5ebb18bab
Version 2 - multibutton
Component | Connected to pin on NodeMCU |
---|---|
GPS VCC | 3V3 |
GPS GND | GND |
GPS RX | D4 |
GPS TX | D3 |
Button1 leg 1 | 3V3 |
Button1 leg 2 | Via resistor (220 ohm) shorting ground and D1 |
Button2 leg 2 | Via resistor (220 ohm) shorting ground and D5 |
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
#include <WiFiClientSecure.h>
/*
This sample sketch demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
It requires the use of SoftwareSerial, and assumes that you have a
4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 0, TXPin = 2;
static const uint32_t GPSBaud = 9600;
//Button
int button = 5;
int button2 = 14;
int buttonpress, buttonpress2 = 0;
//Device ID
String device = "gp001";
String tim = "";
String url = "";
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
//Google Server Setup Section
const char* host = "script.google.com";
const int httpsPort = 443;
WiFiClientSecure client;
const char* fingerprint = "46 B2 C3 44 9C 59 09 8B 01 B6 F8 BD 4C FB 00 74 91 2F EF F6";
String GAS_ID = "AKfycbxtSVvRVh16mXK44mzzjaKJrWrNEdN-eOEmgaibG3ETyvAn_rP6-uaNgUU2mqZXgrsG"; // Replace by your Google App S service id
//Set up to send to GSheets
String readString;
void setup()
{
Serial.begin(115200);
ss.begin(GPSBaud);
pinMode(button, INPUT);
pinMode(button2, INPUT);
WiFiManager wifiManager;
wifiManager.setTimeout(180);
if (!wifiManager.autoConnect("SetupWIFIDataLogger")) {
Serial.println("failed to connect and hit timeout");
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);
}
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
delay(3000);
}
void loop()
{
// This sketch displays information every time a new sentence is correctly encoded.
while (ss.available() > 0)
if (gps.encode(ss.read())) {
// displayInfo();
buttonpress = digitalRead (button);
buttonpress2 = digitalRead (button2);
if (buttonpress != 0) {
Serial.println("button pressed");
//String url = "/macros/s/" + GAS_ID + "/exec?device=" + "pothole" + "&lati=" + String(gps.location.lat(), 6) + "&longi=" + String(gps.location.lng(), 6) + "&time=" + tim;
displayInfo();
}
if (buttonpress2 != 0) {
Serial.println("button2 pressed");
//String url = "/macros/s/" + GAS_ID + "/exec?device=" + "streetlight" + "&lati=" + String(gps.location.lat(), 6) + "&longi=" + String(gps.location.lng(), 6) + "&time=" + tim;
displayInfo();
}
}
if (millis() > 5000 && gps.charsProcessed() < 10)
{
Serial.println(F("No GPS detected: check wiring."));
while (true);
}
}
void displayInfo()
{
Serial.print(F("Location: "));
if (gps.location.isValid())
{
Serial.print(gps.location.lat(), 6);
Serial.print(F(","));
Serial.print(gps.location.lng(), 6);
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" Date/Time: "));
if (gps.date.isValid())
{
Serial.print(gps.date.month());
Serial.print(F("/"));
Serial.print(gps.date.day());
Serial.print(F("/"));
Serial.print(gps.date.year());
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" "));
if (gps.time.isValid())
{
if (gps.time.hour() < 10) Serial.print(F("0"));
Serial.print(gps.time.hour());
Serial.print(F(":"));
if (gps.time.minute() < 10) Serial.print(F("0"));
Serial.print(gps.time.minute());
Serial.print(F(":"));
if (gps.time.second() < 10) Serial.print(F("0"));
Serial.print(gps.time.second());
Serial.print(F("."));
if (gps.time.centisecond() < 10) Serial.print(F("0"));
Serial.print(gps.time.centisecond());
}
else
{
Serial.print(F("INVALID"));
}
Serial.println();
senddata(url);
}
void senddata(String url) {
client.setInsecure();
Serial.print("connecting to ");
Serial.println(host);
if (!client.connect(host, httpsPort)) {
Serial.println("connection failed");
return;
}
if (client.verify(fingerprint, host)) {
Serial.println("certificate matches");
} else {
Serial.println("certificate doesn't match");
}
if (buttonpress != 0) {
url = "/macros/s/" + GAS_ID + "/exec?device=" + "pothole" + "&lati=" + String(gps.location.lat(), 6) + "&longi=" + String(gps.location.lng(), 6) + "&time=" + tim;
}
else if (buttonpress2 != 0) {
url = "/macros/s/" + GAS_ID + "/exec?device=" + "streetlight" + "&lati=" + String(gps.location.lat(), 6) + "&longi=" + String(gps.location.lng(), 6) + "&time=" + tim;
}
//String url = "/macros/s/" + GAS_ID + "/exec?device=" + device + "&lati=" + String(gps.location.lat(), 6) + "&longi=" + String(gps.location.lng(), 6) + "&time=" + tim;
Serial.print("requesting URL: ");
Serial.println(url);
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"User-Agent: BuildFailureDetectorESP8266\r\n" +
"Connection: close\r\n\r\n");
Serial.println("request sent");
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line == "\r") {
Serial.println("headers received");
break;
}
}
String line = client.readStringUntil('\n');
if (line.startsWith("{\"state\":\"success\"")) {
Serial.println("esp8266/Arduino CI successfull!");
} else {
Serial.println("esp8266/Arduino CI has failed");
}
Serial.println("reply was:");
Serial.println("==========");
Serial.println(line);
Serial.println("==========");
Serial.println("closing connection");
}