Hello, I’m using a 3G Electron and have written some code to take sensor data on the analog inputs, store them in a variable, and then allow me to access them via the api link.
After programming I can get several hours (about 16.5 this last time around) of solid connection. After that I get disconnects from the network every 25 minutes.
I set up the SIM card using serial connection, and I have the following lines in my code to keep the connection alive, but it doesn’t seem to be working permanently.
The lowest Particle.keepalive(X) I’ve tried is where X=15, but most of the forum posts I’ve seen have this value at X=240.
Any ideas?
FULL CODE:
//#include "Particle.h"
#include "cellular_hal.h"
STARTUP(cellular_credentials_set("h2g2", "", "", NULL));
//create variables for sensors
const int Moisture_Sensor1 = A3;
const int Moisture_Sensor2 = A4;
const int Light_Sensor1 = A2;
const int readings = 10;//take multiple readings to reduce noise
//initial values for acceleration
double P1_M = 0;
double P2_M = 0;
double L1 = 0;
const int sampleSize = 10;
void setup()
{
Serial.begin(9600);
Particle.keepAlive(15);
Spark.variable("P1_M",&P1_M, DOUBLE);//create spark variable for Plant1 moisture
Spark.variable("P2_M",&P2_M, DOUBLE);//create spark variable for Plant2 moisture
Spark.variable("L1",&L1, DOUBLE);//create spark variable for Light Sensor 1
}
void loop()
{
//call function to give x y and z axis data
P1_M = readSensor(Moisture_Sensor1);
P2_M = readSensor(Moisture_Sensor2);
L1 = readSensor(Light_Sensor1);
delay(100);
}
//--------------------------------------------------------------------------------------------------------------------------------------------
//this function reads data and averages it over packages of samples
int readSensor(int SensorPin)
{
long reading = 0; //initial for reading
analogRead(SensorPin); //analog read axisPin
delay(1); //delay for 1 mS
for (int i = 0; i < sampleSize; i++) //starting at zero and for each reading until predetermined sample size
{
reading += analogRead(SensorPin);
}
return reading/sampleSize;
}
I actually found some code online and sort of forced my functionality into it…
I haven’t really moved forward with cleaning and optimizing the code until I understand the underlying problem of the disconnects for 25 minutes then short reconnects. I might need to switch to a different company for the sim card embedded device.
This might fit the bill and explain why this only happens after a while. The provider might put up with this behaviour for a while but eventually get fed up.
So I won’t conquer your suggestion but concur
I changed the code in 4 ways (updated code at bottom)
#include “Particle.h” //un-commented this line
Particle.keepAlive(240); //changed from 15 to 240
Spark.variable(“P1_M”, P1_M); //removed ‘&’, removed DOUBLE casting (did this for all 3 variables)
Serial.begin(9600); //removed this line
The electron was accessible to my raspberry pi using the api link to get the variables all night until this morning when I got to work:
As you can see my script captures plant moisture and light data every 50 minutes until about 10am. That’s about when I decided to do the manual grabbing of the variables.
After I manually grabbed these variables the device goes into the reset every 25 minutes routine.
I cannot remotely restart the electron (I will try to set that up tonight from my raspberry pi), but could this be my issue? Something in the manual variable query that is causing the electron to reset every 25 minutes?
FULL CODE:
#include "Particle.h"
#include "cellular_hal.h"
STARTUP(cellular_credentials_set("h2g2", "", "", NULL));
//create variables for sensors
const int Moisture_Sensor1 = A3;
const int Moisture_Sensor2 = A4;
const int Light_Sensor1 = A2;
const int readings = 10;//take multiple readings to reduce noise
//initial values for acceleration
double P1_M = 0;
double P2_M = 0;
double L1 = 0;
const int sampleSize = 10;
void setup()
{
Particle.keepAlive(240);
Spark.variable("P1_M", P1_M);//create spark variable for Plant1 moisture
Spark.variable("P2_M", P2_M);//create spark variable for Plant2 moisture
Spark.variable("L1", L1);//create spark variable for Light Sensor 1
}
void loop()
{
//call function to give x y and z axis data
P1_M = readSensor(Moisture_Sensor1);
P2_M = readSensor(Moisture_Sensor2);
L1 = readSensor(Light_Sensor1);
delay(100);
}
//--------------------------------------------------------------------------------------------------------------------------------------------
//this function reads data and averages it over packages of samples
int readSensor(int SensorPin)
{
long reading = 0; //initial for reading
analogRead(SensorPin); //analog read axisPin
delay(1); //delay for 1 mS
for (int i = 0; i < sampleSize; i++) //starting at zero and for each reading until predetermined sample size
{
reading += analogRead(SensorPin);
}
return reading/sampleSize;
}
hey @ScruffR where can I find documentation of the correct way to use this command in the "modern" way?
The "modern" syntax would be Particle.variable("P1_M", P1_M).
Everything I see online has the old was with the ampersands before the second variable.
Do I have to cast it as an INT or is that assumed default casting?
@bluesforsalvador, the docs shows the "new" way at the beginning and end with the "old" way with this caveat:
Prior to 0.4.7 firmware, variables were defined with an additional 3rd parameter to specify the data type of the variable. From 0.4.7 onward, the system can infer the type from the actual variable. Additionally, the variable address was passed via the address-of operator (&). With 0.4.7 and newer, this is no longer required.
This is the pre-0.4.7 syntax:...
What frequency should I be allowed to use this to get access to my variables? https://api.particle.io/v1/devices/DEVICE/P1_M/?access_token=ACCESSTOKEN
I’m trying every 10 minutes from my raspberry pi python code using unirest, but I get a timeout most of the time.
I seem to be able to get access to the variables for a short time every 50 minutes.
You should be able to get them once a second (though you might not want to poll that often, so be a good netizen). It’s more likely that your device only stays online for so long at a time, thus the variables being unavailable in the mean time.
@bluesforsalvador, you should be able to hit it every second! First, you can add #include "Particle.h" though that is also done automatically by the Web IDE.
Second, remove the delay(100); in your loop and create a non-blocking delay like this:
unsigned long sampleInterval = 0; // global variable
void loop()
{
if (millis() - sampleInterval >= 100) { // wait 100ms or whatever before sampling
sampleInterval = millis();
//call function to give x y and z axis data
P1_M = readSensor(Moisture_Sensor1);
P2_M = readSensor(Moisture_Sensor2);
L1 = readSensor(Light_Sensor1);
}
}
In readSensor(), you do an “empty” analogRead(SensorPin), wait 1ms then read the same pin multiple times and average. Any reason for that? Is this to “prime” the ADC? Not sure you need this approach or the 1ms delay.
I was looking into the non-blocking delay doing some searches on the web yesterday, I haven’t had a chance to implement this yet though.
The empty read + the averaging isn’t really necessary for plant moisture or light level applications. This code was originally used to read an accelerometer and I just left that part in.
I think just doing 1 read would suffice, but I think the delay is to allow the device time to read from the ADC and store it before returning the contents of the variable. Do I need this delay or not?
Here’s the code that’s currently on the device:
#include "Particle.h"
#include "cellular_hal.h"
STARTUP(cellular_credentials_set("h2g2", "", "", NULL));
//create variables for sensors
const int Moisture_Sensor1 = A3;
const int Moisture_Sensor2 = A4;
const int Light_Sensor1 = A2;
const int readings = 10;//take multiple readings to reduce noise
//initial values for acceleration
double P1_M = 0;
double P2_M = 0;
double L1 = 0;
const int sampleSize = 10;
void setup()
{
Particle.keepAlive(240);
Particle.variable("P1_M", P1_M);//create spark variable for Plant1 moisture
Particle.variable("P2_M", P2_M);//create spark variable for Plant2 moisture
Particle.variable("L1", L1);//create spark variable for Light Sensor 1
}
void loop()
{
//call function to give x y and z axis data
P1_M = readSensor(Moisture_Sensor1);
P2_M = readSensor(Moisture_Sensor2);
L1 = readSensor(Light_Sensor1);
delay(100);
}
//--------------------------------------------------------------------------------------------------------------------------------------------
//this function reads data and averages it over packages of samples
int readSensor(int SensorPin)
{
long reading = 0; //initial for reading
analogRead(SensorPin); //analog read axisPin
delay(1); //delay for 1 mS
for (int i = 0; i < sampleSize; i++) //starting at zero and for each reading until predetermined sample size
{
reading += analogRead(SensorPin);
}
return reading/sampleSize;
}
Here’s the code I shall program tonight: (I’d program it OTA now, but for some reason I always need to put the device into safe mode (blinking magenta) in order to OTA program, is there a reason for this?
//#include "Particle.h"
#include "cellular_hal.h"
STARTUP(cellular_credentials_set("h2g2", "", "", NULL));
//create variables for sensors
const int Moisture_Sensor1 = A3;
const int Moisture_Sensor2 = A4;
const int Light_Sensor1 = A2;
const int readings = 10;//take multiple readings to reduce noise
//create a variable to perform non-blocking delay
unsigned long sampleInterval = 0; // global variable
//initial values for acceleration
double P1_M = 0;
double P2_M = 0;
double L1 = 0;
const int sampleSize = 10;
void setup()
{
Particle.keepAlive(240);
Particle.variable("P1_M", P1_M);//create spark variable for Plant1 moisture
Particle.variable("P2_M", P2_M);//create spark variable for Plant2 moisture
Particle.variable("L1", L1);//create spark variable for Light Sensor 1
}
void loop()
{
if (millis() - sampleInterval >= 100) { // wait 100ms or whatever before sampling
sampleInterval = millis();
//call function to give x y and z axis data
P1_M = readSensor(Moisture_Sensor1);
P2_M = readSensor(Moisture_Sensor2);
L1 = readSensor(Light_Sensor1);
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------
//this function reads data and averages it over packages of samples
int readSensor(int SensorPin)
{
long reading = 0; //initial for reading
reading = analogRead(SensorPin); //analog read axisPin
return reading/sampleSize;
}
@bluesforsalvador, you don't need the sampling delay since the analogRead() function only returns when the reading is completed (blocking).
I noticed you are defining your Particle.variables as doubles (double precision floating point) but your calculations for the values are integers. Which format does your server need as this will affect your calculation "chain".
This concerns me as I don't see any obvious reasons for your code to be blocking the OTA. Nonetheless, I suggest you add SYSTEM_THREAD(ENABLED); after the STARTUP() line to allow the system and user firmware to run in their own threads.
you don't need the sampling delay since the analogRead() function only returns when the reading is completed (blocking).
Ahh good to know, I'll remove the delay as well
re: doubles
I forgot to remove the casting of those variables as doubles. Thanks for pointing that out, though I don't see it casuing an issue.
//initial values for acceleration
int P1_M = 0;
int P2_M = 0;
int L1 = 0;
I also changed the "long" to an "int" in the function:
My Server code expects an INT which it then divides by 4095 and then multiplies by 100 to provide a percentage.
int readSensor(int SensorPin)
{
int reading = 0; //initial for reading
reading = analogRead(SensorPin); //analog read axisPin
return reading;
}
re: safe mode programming
I've added a note to add SYSTEM_THREAD(ENABLED); after STARTUP(); as you suggested. I'll try this tonight when I get home to see if it works.
//#include "Particle.h"
#include "cellular_hal.h"
STARTUP(cellular_credentials_set("h2g2", "", "", NULL));
SYSTEM_THREAD(ENABLED);
//create variables for sensors
const int Moisture_Sensor1 = A3;
const int Moisture_Sensor2 = A4;
const int Light_Sensor1 = A2;
const int readings = 10;//take multiple readings to reduce noise
//create a variable to perform non-blocking delay
unsigned long sampleInterval = 0; // global variable
//initial values for acceleration
int P1_M = 0;
int P2_M = 0;
int L1 = 0;
void setup()
{
Particle.keepAlive(240);
Particle.variable("P1_M", P1_M);//create spark variable for Plant1 moisture
Particle.variable("P2_M", P2_M);//create spark variable for Plant2 moisture
Particle.variable("L1", L1);//create spark variable for Light Sensor 1
}
void loop()
{
if (millis() - sampleInterval >= 100) { // wait 100ms or whatever before sampling
sampleInterval = millis();
//call function to give x y and z axis data
P1_M = readSensor(Moisture_Sensor1);
P2_M = readSensor(Moisture_Sensor2);
L1 = readSensor(Light_Sensor1);
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------
//this function reads data and averages it over packages of samples
int readSensor(int SensorPin)
{
int reading = 0; //initial for reading
reading = analogRead(SensorPin); //analog read axisPin
return reading;
}