Example: Logging and graphing data from your Spark Core using Google


#184

Alright fellas, I gotcha. I thought you were recommending against the delay() because it wouldn’t work at all (when I tried it using delay(), the RGB started blinking red and froze), not because of the problem that delaying inside of an ISR presents. Trying to take the easy way out here since I don’t know what putting a flag inside of an ISR and reading it in the loop means or entails. But, time to learn something else. I appreciate the direction and thought I might have found something in the docs that @ScruffR wasn’t aware of! Yeah right. @Moors7, I dig the blink duration reference. I’m an eye doc by trade. Just moonlighting as a programming student.

@peekay123, you are correct, I don’t care about missing a bubble or two. No biggie there.


#185

That’s true - delay() in an ISR will crash your application, but also any unnecessary other waiting should be avoided wherever possible.

It’s no big deal

volatile int count;
volatile bool needToBlink;

void bubbleCounting (void) {
    count ++;
    needToBlink = true;
}

void loop() {
  // whatever else you want to do

  if (needToBlink)
  {
    needToBlink = false;
    digitalWrite(Led2,  HIGH);
    delay(100);
    digitalWrite(Led2, LOW);
  }
}

That was it :wink:


#186

Very cool. Very cool, indeed. I’ll fire this thing up and see what kind of battery life we get now. Thanks for all the help (education).


#187

Hi guys, I’m having a little trouble logging data about cellular strength using Particles’s asset tracker. My code verifies fine, but then I have a little trouble using postman (I’m new to all of this and have never used a RESTFUL client). I put in the URL and my results look like this:

{
"id": "310057000a51343334363138",
"name": "hardware-test-electron",
"last_app": null,
"last_ip_address": "176.83.209.122:27792",
"last_heard": "2016-06-20T14:25:14.862Z",
"product_id": 10,
"connected": true,
"platform_id": 10,
"cellular": true,
"status": "normal",
"last_iccid": "8934076500002751634",
"imei": "353162071295662",
"current_build_target": "0.4.8"
}

It seems like maybe I need to be asking postman to output the results?

My code is here:

    char resultstr[64];
    String voltage = "0"; // Variable to keep track of LiPo voltage
    String soc = "4"; // Variable to keep track of LiPo state-of-charge (SOC)
    bool alert; // Variable to keep track of whether alert has been triggered

    void setup()
    {
	Serial.begin(9600); // Start serial, to output debug data

	delay(3000);
	pinMode(D0, INPUT_PULLUP);
	pinMode(D1, INPUT_PULLUP);
    
	// Set up the MAX17043 LiPo fuel gauge:
	Serial.print("Error: ");
	Serial.println(lipo.begin()); // Initialize the MAX17043 LiPo fuel gauge


	// Set up Spark variables (voltage, soc, and alert):
	Particle.variable("voltage", voltage);
	Particle.variable("soc", soc);
	Particle.variable("alert", alert);
	// To read the values from a browser, go to:
	// http://api.particle.io/v1/devices/{DEVICE_ID}/{VARIABLE}?access_token={ACCESS_TOKEN}
    

	// Quick start restarts the MAX17043 in hopes of getting a more accurate
	// guess for the SOC.
	lipo.quickStart();

	// We can set an interrupt to alert when the battery SoC gets too low.
	// We can alert at anywhere between 1% - 32%:
	lipo.setThreshold(20); // Set alert threshold to 20%.
	pinMode(D6, OUTPUT);
	digitalWrite(D6, LOW);
    }

    void loop()
    {
	// digitalWrite(D6, LOW);
	lipo.quickStart();
	// lipo.getVoltage() returns a voltage value (e.g. 3.93)
	voltage = String(lipo.getVoltage());
	// lipo.getSOC() returns the estimated state of charge (e.g. 79%)
	soc = String(lipo.getSOC());
	// lipo.getAlert() returns a 0 or 1 (0=alert not triggered)
	alert = lipo.getAlert();
	// format your data as JSON, don't forget to escape the double quotes
	sprintf(resultstr, "{\"data1\":%s,\"data2\":%s,\"data3\":%s}", *voltage, *soc, alert);
	//serial.println("Voltage: %d\nSoc: %d\nalert:%d \n", voltage, soc, alert);
	delay(1000); // wait for a second
    }

Any ideas? When I try to run the script on google in throws an error:
Request failed for https://api.spark.io/v1/devices/MY-DEVICE-ID/result?


#188

First you should move your Particle.variable() statements further up in setup() especially before the delay().
Then consider moving on to 0.5.1 instead of the outdated 0.4.8 your device info shows.

And I guess you should wrap your values in double quotes and use the correct type like this

  snprintf(resultstr, sizeof(resultstr), "{\"data1\":\"%s\",\"data2\":\"%s\",\"data3\":\"%d\"}", (const char*)voltage, (const char*)soc, alert);
  Serial.println(resultstr);

And finally you’d need your access_token when requesting data from the cloud like this (and you might want to transition from api.spark.io to api.particle.io)

https://api.particle.io/v1/devices/MY-DEVICE-ID/result?access_token=<yourAccessToken>

#189

Thanks so much for the help @ScruffR. I’ve moved the Particle.variable() up and updated the firmware, and updated the variable printing (I’ve pasted my updated code below). Now when I call https://api.particle.io/v1/devices/MY-DEVICE-ID/result?access_token=<yourAccessToken> I get the result:

    {
    "error": "invalid_token",
    "error_description": "The access token provided is invalid."
    }

But, if I run https://api.spark.io/v1/devices?access_token=yourAccessToken I get all my device info such as:

{
    "id": "My device ID",
    "name": "Asset_Tracker_1",
    "last_app": null,
    "last_ip_address": "176.83.136.134:7765",
    "last_heard": "2016-06-23T14:25:13.019Z",
    "product_id": 10,
    "connected": true,
    "platform_id": 10,
    "cellular": true,
    "status": "normal",
    "last_iccid": "8934076500002593770",
    "imei": "353162071112875",
    "current_build_target": "0.5.1",
    "pinned_build_target": "0.5.1"
},

Any ideas?

    #include "application.h"
    #include "SparkFunMAX17043/SparkFunMAX17043.h" // Include the SparkFun MAX17043 library

    char resultstr[64];
    String voltage = "0"; // Variable to keep track of LiPo voltage
    String soc = "4"; // Variable to keep track of LiPo state-of-charge (SOC)
    bool alert; // Variable to keep track of whether alert has been triggered

    void setup()
    {
	Serial.begin(9600); // Start serial, to output debug data
	
	// Set up Spark variables (voltage, soc, and alert):
	Particle.variable("voltage", voltage);
	Particle.variable("soc", soc);
	Particle.variable("alert", alert);

	delay(3000);
    pinMode(D0, INPUT_PULLUP);
    pinMode(D1, INPUT_PULLUP);
    
	// Set up the MAX17043 LiPo fuel gauge:
	Serial.print("Error: ");
	Serial.println(lipo.begin()); // Initialize the MAX17043 LiPo fuel gauge

	// Quick start restarts the MAX17043 in hopes of getting a more accurate
	// guess for the SOC.
	lipo.quickStart();

	// We can set an interrupt to alert when the battery SoC gets too low.
	// We can alert at anywhere between 1% - 32%:
	lipo.setThreshold(20); // Set alert threshold to 20%.
	pinMode(D6, OUTPUT);
	digitalWrite(D6, LOW);
    }

    void loop()
    {

    lipo.quickStart();// digitalWrite(D6, LOW);
	
	voltage = String(lipo.getVoltage()); // lipo.getVoltage() returns a voltage value (e.g. 3.93)
	soc = String(lipo.getSOC());// lipo.getSOC() returns the estimated state of charge (e.g. 79%)
	alert = lipo.getAlert();// lipo.getAlert() returns a 0 or 1 (0=alert not triggered)
    
    // formating data as JSON
    snprintf(resultstr, sizeof(resultstr), "{\"data1\":\"%s\",\"data2\":\"%s\",\"data3\":\"%d\"}", (const char*)voltage, (const char*)soc, alert);
    Serial.println(resultstr);
   
    delay(1000); // wait for a second
    }

#190

Have you double-checked this yet?


#191

I’ve tried it a few times, and then reset the access token and tried again a few times. I think it must be correct as the https://api.spark.io/v1/devices?access_token=yourAccessToken works fine with the same access token


#192

There might be some other things wrong with this request.
I can’t see a Particle.variable() named result in your code, you may have a mistake in your device ID in that request and since you once use access_token=<yourAccessToken> and another time access_token=yourAccessToken, just for clarity, the angled brakets are not part of the request.


#193

Thanks so much for the help. I’m very new to all of this. My mistake was using the the angled brackets and not including result! My electron now publishes to my google spreadsheet! :grinning:

Now on to the next part. Maybe I should start a new thread? I want to Electron to log the quality and strength of its cellular signal (The purpose being I can send this module to clients, they can turn it on and leave it running for a couple days and I can evaluate cellular strength remotely). I think the code I need is something along the lines of:

CellularSignal signal = Cellular.RSSI();
Particle.publish("RSSI", String(signal.rssi));
Particle.publish("Qual", String(signal.qual));

But when I try putting that in my loop, although the code verifies, I get: "error": "Timed out." on Postman when I run the Get request. I tried formatting everything like the voltage, soc, and alert variables instead of events, but didn’t understand what I was doing…

#include "application.h"
#include "SparkFunMAX17043/SparkFunMAX17043.h" // Include the SparkFun MAX17043 library

char resultstr[64];
String voltage = "0"; // Variable to keep track of LiPo voltage
String soc = "4"; // Variable to keep track of LiPo state-of-charge (SOC)

void setup()
{
Serial.begin(9600); // Start serial, to output debug data

// Set up Spark variables (voltage, soc, and alert):
Particle.variable("voltage", voltage);
Particle.variable("soc", soc);
Particle.variable("result", resultstr, STRING);


delay(3000);
pinMode(D0, INPUT_PULLUP);
pinMode(D1, INPUT_PULLUP);

// Set up the MAX17043 LiPo fuel gauge:
Serial.print("Error: ");
Serial.println(lipo.begin()); // Initialize the MAX17043 LiPo fuel gauge

// Quick start restarts the MAX17043 in hopes of getting a more accurate
// guess for the SOC.
lipo.quickStart();

// We can set an interrupt to alert when the battery SoC gets too low.
// We can alert at anywhere between 1% - 32%:
lipo.setThreshold(20); // Set alert threshold to 20%.
pinMode(D6, OUTPUT);
digitalWrite(D6, LOW);
}

void loop()
{

CellularSignal signal = Cellular.RSSI();
Particle.publish("RSSI", String(signal.rssi));
Particle.publish("Qual", String(signal.qual));

// digitalWrite(D6, LOW)
lipo.quickStart();

// lipo.getVoltage() returns a voltage value (e.g. 3.93)
voltage = String(lipo.getVoltage());
// lipo.getSOC() returns the estimated state of charge (e.g. 79%)
soc = String(lipo.getSOC());
// format your data as JSON, don't forget to escape the double quotes
snprintf(resultstr, sizeof(resultstr), "{\"data1\":\"%s\",\"data2\":\"%s\",\"data3\":\"%s\"\"data4\":\"%s\"}", (const char*)voltage, (const char*)soc, signal.rssi, signal.qual);
Serial.println(resultstr);

delay(1000); // wait for a second
}

#194

You are exceeding the rate limit of max 1 publish per second.
If you put both values together into one publish you might have more luck.


#195

Hi guys, I’m back with a couple questions. I’ve formatted my particle so that it outputs the cellular signal, but I seem to be having a little trouble getting it to actually add to the spreadsheet. When I put my postman request in, I get these results:

{
"cmd": "VarReturn",
"name": "result",
"result": "{data1: -73 \n data2: 37}",
"coreInfo": {
"last_app": "",
"last_heard": "2016-07-14T13:49:55.945Z",
"connected": true,
"last_handshake_at": "2016-07-14T13:32:05.070Z",
"deviceID": "MY-DEVICE-ID",
"product_id": 10
 }
}

And when I run the script, I get these results:


But it doesn;t seem to be updated the spreadsheet at all. Any ideas? My two Codes are pasted below. Thanks so much for all the help:

#include "AssetTracker/AssetTracker.h"


//Device sleep time, minutes between publishes
int delayMinutes = 1;
 char resultstr[64];

//AssetTracker
AssetTracker t = AssetTracker();

FuelGauge fuel;
int rssi;

void setup() {

//Begin AssetTracker
t.begin();

//Enable the GPS module
//Takes 1.5s or so because of delays
t.gpsOn();

Particle.variable("result", resultstr);
}

void loop() {

//Need to capture the GPS output every loop
t.updateGPS();


    //Read and Publish lat/long
    Particle.publish("LatLong", t.readLatLon(), 60, PRIVATE);

    
    //Read and publish battery state
    //Formatted "Cell votlage, state of charge %"
    Particle.publish("Battery",String(fuel.getVCell()) + String(fuel.getSoC()), 60, PRIVATE);
    
    //Read and Publish cell strength
    //Formatted "RSSI (-113dBm to -51dBm), quality (0-49))"
    CellularSignal rssi = Cellular.RSSI();
    Particle.publish("RSSI", String(rssi), 60, PRIVATE);

    snprintf(resultstr, sizeof(resultstr), "{\"Rssi\":%d,\"Qual\":%d,\"data3\":}", rssi.rssi, rssi.qual);
    Serial.println(resultstr);

}

And here is my script code:

 function collectData() {
 var  sheet = SpreadsheetApp.getActiveSheet();

 var response =   UrlFetchApp.fetch("https://api.particle.io/v1/devices/MY-DEVICE-ID/result?access_token=MY-ACCESS-TOKEN");

 try {
var response = JSON.parse(response.getContentText()); // parse the JSON the Core API created
var result = unescape(response.result); // you'll need to unescape before your parse as JSON

try {
  var p = JSON.parse(result); // parse the JSON you created
  var d = new Date(); // time stamps are always good when taking readings
  sheet.appendRow([d, p.data1, p.data2]); // append the date, data1, data2 to the sheet
} catch(e)
{
  Logger.log("Unable to do second parse");
}
 } catch(e)
 {
    Logger.log("Unable to returned JSON");
  }
 }

#196

Any ideas?


#197

Hi @binaryfrost thanks for the great project share.

I got completely stuck with the Spark.variable(“result”, &resultstr, STRING);
and was wondering if you (or anyone else here) could have a look at my code to see what Im not seeing.

I don’t know if it’s customary that people directly paste code in a post so I wanted to check first.
Thanks


#198

Yes, it is customary (and necessary) to post the code you’re having trouble with. Also, please elaborate on what “got completely stuck” means. What’s the problem? Does the code not work, or do you not know how to write the code?


#199

Hi @Ric Thanks for your reply. Below my code, I’ve made as many notes as possible so you can see where the problem is (I hope). Everything work but I get stuck when enter: Spark.variable(“result”, &resultstr, STRING); Marked in the code between // PROBLEM STARTS HERE JDM and // PROBLEM ENDS HERE JDM.
It would be great if you have any idea how I can take this forward. Many thanks.

Ps: No idea why some of the code is posted in grew boxes and some not
I am fairly new to all this but having the time of my life :sunglasses:



/**
 * ReadSHT1xValues
 *
 * Read temperature and humidity values from an SHT1x-series (SHT10,
 * SHT11, SHT15) sensor.
 *
 * Copyright 2009 Jonathan Oxer <jon@oxer.com.au>
 * www.practicalarduino.com
 * 
 * Aditional code/changes made by Jaap de Maat (JDM)
 *
 * Ported to Spark Core by Anurag Chugh (https://github.com/lithiumhead) on 2014-10-15
 */
 
 
 
 // This #include statement was automatically added by the Spark IDE.
#include "SHT1x/SHT1x.h"
 
 
 
 
 // TRY THIS TRY THIS
 
 char resultstr[64]; // Part needed to Connect data to a google doc spreadsheet // JDM add

unsigned long wait = millis();              //Delay timer to create a non-delay() x-second sampling timer
const unsigned long waittime = 5000L;


 // TRY THIS TRY THIS
 

// Specify data and clock connections and instantiate SHT1x object
#define dataPin  D0
#define clockPin D1
// #define MOISTPIN_1 D3      // Pin where the soil moisture sensor is connected  // JDM add - Still in development


//Set two LED lights
int led1 = D7; // led 1 // JDM add
int led2 = D6; // led 2 // JDM add
// int sensorPin = D3; //soil moisture sensor is connected  // JDM add - Still in development


// No idea what this is JDM
SHT1x sht1x(dataPin, clockPin);





void setup()
{
 
    
       Serial.begin(9600); // Open serial connection to report values to host
       Serial.println("Starting up");
            
        pinMode(led1, OUTPUT);
        pinMode(led2, OUTPUT);
    
    
                         // Connect data to a google doc spreadsheet // JDM add
                     // Code by binaryfrost from: https://community.particle.io/t/example-logging-and-graphing-data-from-your-Particle-core-using-google/2929
      
                     //pinMode(A0, INPUT); // setup A0 as analog input // JDM add
                     //pinMode(A1, INPUT); // setup A1 as analog input // JDM add
                     // expose your char buffer to the Cloud API // JDM add
                     
                     
                     // PROBLEM STARTS HERE JDM
                     
              //        Spark.variable("result", &resultstr, STRING);  // JDM add
    
    
                       // PROBLEM END HERE JDM
    
    
    
}

void loop()
{
    float temp_c;
    float temp_f;
    float humidity;
    
    // Read values from the sensor
    temp_c = sht1x.readTemperatureC();
    humidity = sht1x.readHumidity();
    
    // Print the values to the serial port
    Serial.print("Temperature: ");
    Serial.print(temp_c, 2);
    Serial.print("C / ");

    Serial.print("Humidity: ");
    Serial.print(humidity);
    Serial.println("%");
    
    
         // Send a publish...
        Particle.publish("Temperature C", String(temp_c, 1), 60, PRIVATE);
        Particle.publish("Humidity %", String(humidity, 0), 60, PRIVATE);
    
    
// Simply blinking some LED light in each loop // added by JDM

            digitalWrite(led1, HIGH);   // turn the LED on (HIGH is the voltage level)
            delay(250);  
            digitalWrite(led2, HIGH);   // turn the LED on (HIGH is the voltage level)
            delay(250);              // wait for a second
            digitalWrite(led1, LOW);    // turn the LED off by making the voltage LOW
            delay(250);  
            digitalWrite(led2, LOW);    // turn the LED off by making the voltage LOW

// Delay for 10 sec before next reading // added by JDM
delay(10000); 
    
}

#200

I see several things that may be the problem, though you still haven’t told me what “getting stuck” means. What happens when you uncomment the code that you say is the problem?

I don’t know where you got this code, but you should definitely check out the docs to make sure you’re using the current api. Spark has been depreciated (but it still might work), so you should use Particle instead. Also, there’s no longer any need to use the “&”, or specify the type of the variable. The line should be,

Particle.variable("result", resultstr);

That line registers the variable with the cloud, but I don’t see anywhere in your code where you set the value of resultstr to anything.


#201

Hi @Ric Thanks for your quick reply!
The code is part of a library (found in the Particle Build library) for the Sparkfun sht1x.

As you suggested I’ve changed: Spark.variable(“result”, &resultstr, STRING); to Particle.variable(“result”, resultstr); and I don’t get any more error message when verifying, so the is a good sign.

What I met by “getting stuck” is basically that error message (only when it’s uncommented) sorry for not being more clear on that.

As mentioned it does look alright now so Im gonna go ahead a get further going with it. Thanks again for you help. Much appreciated. In case I “get stuck” again, I be more clear and might ask for you advise again if that ok.

All the best,
J


#202

@Ric I am very excited to let you know I allready got to the results I wanted!
And learned lots in doing so. Massive thanks to you for your help.

Next part of the project is going to be uploading the data to http://wunderground.com
All the best,
J


#203

Hi @peekay123 Would you be able to tell me how you got decimals into your reading?
Many thanks, j