Greetings,
I am using an Electron to take readings from a Maxbotix sonar sensor to read the height of a stream every 15 minutes, and then upload that information to data.sparkfun.com. Each reading is identified by number, so I am trying to track this with a retained variable that will survive the deep sleep I put the unit in every 15 minutes. Unfortunately, on every upload the number remains 1.
Here is the code:
STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));
SYSTEM_MODE(SEMI_AUTOMATIC);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
#define VERSION "0.5e-160323.1308" // Major version-build date.build time
const int HEIGHT = 184; // Height of top of octagonal gasket, in cm
#define SPARKFUN_PUBLIC_KEY "XXXXXXXXXXXXXXXXXX"
#define SPARKFUN_PRIVATE_KEY "XXXXXXXXXXXXXXXXXX"
#define UTCOFFSET -4 // Local time offset from UTC.
#define UPLOADINTERVAL 15 // Interval, in minutes, between uploads
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
#include "SparkFunPhant.h"
#include "SparkTime.h"
#define SERVER "data.sparkfun.com"
#define PULSEPIN D1 // Pulse width data pin from sonar
retained int readingNumber; // Tracking the reading/upload number
int pulse; // Length of return pulse from the sonar
int pulseMode; // The mathematical mode of pulse set
const byte arraysize = 7; // Array for sonar values (must be odd for mode)
int rangevalue[] = {0, 0, 0, 0, 0, 0, 0}; // Initial array for sonar
int streamHeight = 0; // Height of the stream being monitored
int connectFailed = 0; // Tracking the number of failed upload attempts
int badReq = 0;
int unexpRes = 0;
bool uploaded = false;
const unsigned int timeoutInterval = 20000; // Period, in ms, to wait for connection
Phant phant (SERVER, SPARKFUN_PUBLIC_KEY, SPARKFUN_PRIVATE_KEY);
FuelGauge fuel;
UDP UDPClient;
void setup()
{
Serial.begin(57600); // Begin the Serial interface
Serial.print ("Hidrosonico version ");
Serial.println (VERSION);
Serial.print ("Particle firmware version ");
Serial.println (System.version());
pinMode (PULSEPIN, INPUT); // Sonar pulse width pin
Time.zone (UTCOFFSET); // Set the local time zone
}
void loop()
{
// If this is not a designated upload minute and the uploaded flag is up,
// put the flag down
if(Time.minute() % UPLOADINTERVAL != 0 && uploaded == true)
{
uploaded = false; // Reset the flag to false in prep for next upload
}
// If this is a designated upload minute, and we have not already uploaded
// this minute, take and upload a reading.
if (Time.minute() % UPLOADINTERVAL == 0 && uploaded == false)
{
readingNumber++; // Increment the reading counter
takeReading(); // Take a reading before turning on GSM
if (Particle.connected() == false)
{
Particle.connect();
}
Serial.println (Time.timeStr()); // Print the time for confirmation
Serial.printf("Stream height: %d", streamHeight);
uploadData();
}
// Usually we will leave the GSM module off to save power, but this means we
// will not be able to reflash the firmware OTA. We will turn the module on
// for two hours during the day to enable OTA reflash.
bool otaWindow;
if (Time.hour() == 10 || Time.hour() == 16) // These will be the hours of the OTA upload break
{
if (otaWindow == false) // If the window was closed...
{
Particle.publish ("OTA_window_open", PRIVATE);
}
otaWindow = true;
}
else
{
if (otaWindow == true) // If the window was open....
{
Particle.publish ("OTA_window_closed", PRIVATE);
}
otaWindow = false;
}
if (otaWindow == false && uploaded == true) // Provided we're not on an OTA upload break...
{
uploaded = false;
Serial.printf ("Next upload in %d seconds. Sleeping...", sleepTime);
Serial.flush(); // For future implementation by Particle
wait (10); // Because flush() is not yet implemented
System.sleep(SLEEP_MODE_DEEP, ((((UPLOADINTERVAL * ((Time.minute()/UPLOADINTERVAL) + 1)) - Time.minute()) * 60) - Time.second()));
}
}
void takeReading()
{
Serial.print(F("Taking readings..."));
for(int readingCount = 0; readingCount < arraysize; readingCount++)
{
/* The MaxSonar measures the distance of objects by bouncing a
superaudible pulse off the object and measuring the time of flight
(TOF) between the emission of the pulse and its return. For the
MB7369, 1 microsecond TOF = 1mm of distance. For more see:
http://www.maxbotix.com/articles/085-pt5.htm#codes*/
pulse = pulseIn(PULSEPIN, HIGH); // Returns length of pulse in us
Serial.printf ("Reading %d: %d", readingCount, pulse);
rangevalue[readingCount] = pulse;
wait (10); // Short delay before next pulse reading
}
// Take mode of readings to smooth out any errors or noise
pulseMode = mode(rangevalue, arraysize);
Serial.printf ("pulseMode: %d", pulseMode);
streamHeight = HEIGHT - (pulseMode / 10);
Serial.println ("done.");
}
int mode(int * x, int n) // Calculate the mode of an array of readings
{
int i = 0;
int count = 0;
int maxCount = 0;
int mode = 0;
int bimodal;
int prevCount = 0;
while(i < (n - 1))
{
prevCount = count;
count = 0;
while(x[i] == x[i + 1])
{
count++;
i++;
}
if(count > prevCount && count > maxCount)
{
mode = x[i];
maxCount = count;
bimodal = 0;
}
if(count == 0)
{
i++;
}
if(count == maxCount) // If the dataset has 2 or more modes
{
bimodal = 1;
}
if(mode == 0 || bimodal == 1) // Return the median if no mode
{
mode = x[(n / 2)];
}
return mode;
}
}
int postToPhant()
{
phant.add("1_reading", readingNumber);
phant.add("2_streamheight", streamHeight);
phant.add("3_voltage", fuel.getVCell());
phant.add("4a_connectfailed", connectFailed);
phant.add("4b_badreq", badReq);
phant.add("4c_unexpres", unexpRes);
TCPClient client;
char response[512];
int i = 0;
int retVal = 0;
if (client.connect(SERVER, 80)) // Connect to the server
{
// Post message to indicate connect success
Serial.println (F("Posting..."));
// phant.post() will return a string formatted as an HTTP POST.
// It'll include all of the field/data values we added before.
// Use client.print() to send that string to the server.
client.print (phant.post());
Serial.print (phant.post());
wait (15000);
// Now we'll do some simple checking to see what (if any) response
// the server gives us.
while (client.available())
{
char c = client.read();
Serial.print(c); // Print the response for debugging help.
if (i < 512)
response[i++] = c; // Add character to response string
}
// Search the response string for "200 OK", if that's found the post
// succeeded.
if (strstr(response, "200 OK"))
{
Serial.println (F("Post success!"));
retVal = 1;
}
else if (strstr(response, "400 Bad Request"))
{ // "400 Bad Request" means the Phant POST was formatted incorrectly.
// This most commonly ocurrs because a field is either missing,
// duplicated, or misspelled.
Serial.println (F("Bad request"));
retVal = -1;
badReq++;
}
else
{
// Otherwise we got a response we weren't looking for.
Serial.println (F("Unexpected response"));
retVal = 1;
unexpRes++;
}
}
else
{ // If the connection failed, print a message:
Serial.println (F("Connection failed"));
retVal = -3;
connectFailed++;
}
client.stop(); // Close the connection to server.
return retVal; // Return error (or success) code.
delay (500);
}
void uploadData()
{
int attempts = 0;
while (postToPhant() != 1 && attempts < 5)
{
attempts++;
if (attempts > 1)
{
wait (1000);
Particle.process();
}
}
Particle.publish ("streamheight", (String)streamHeight);
uploaded = true;
}
void wait(unsigned long period)
{
/* Interrupts cannot trigger during a delay(). This function serves the same purpose
without locking up the clock. */
unsigned long waitEnd = millis() + period;
while (millis() < waitEnd){};
}
long sleepTime()
{
return ((((UPLOADINTERVAL * ((Time.minute()/UPLOADINTERVAL) + 1)) - Time.minute()) * 60) - Time.second());
}
The output looks like:
1_reading 2_streamheight 3_voltage
1 184 4.0109
1 184 4.0122
1 184 4.0085
Any advice appreciated.