Open holomorph opened 6 years ago
Hi! Maybe I could help you... So:
Do you read incoming data from SARA? I guess incoming buffer gets full and SARA stops Arduino in an infinite loop.
Also I think your first code is better but I would improve with the following:
if (now - then >= period) {
If you put all in the main loop I think it will become more stable.
Hope it helps!
Thanks, GSM and GPRS status gets checked in setup()
which seems fine, but using the first code I inserted the following into loop()
before if (now - then >= period) {
to count bytes read/look at the response:
while (client.available()) {
char c = client.read();
// Serial.print(c);
bytes_read++;
}
Lots of useless headers in the response, 849 bytes! Did some experimenting and found that it takes needing period
to be in excess of 3000ms for the entire response to be read before another HTTP request is sent, which is unfortunate because I'd like it to be 1000ms. Perhaps the server can be configured to send less junk back.
Does client.flush()
do anything? Normally I'd expect such a function to read()
until there's nothing left (one might think the snippet above should achieve that), but I see the function body is empty.
Hi! yes GSM and GPRS are checked in setup()
but their state can change... even the socket could get closed or whatever... so i think I has to be checked.
About response... a better approach is read from client using a buffer instead of char by char. About the headers, in my case opted to make my own socket server, it's more complicated but thus there's no need to send/receive all http junk only required bytes then all becomes faster. Instead, you could try to remove headers from server maybe the safer option. All in all if you use buffering reading data from socket it will become considerably faster.
A buffer example taken from #12 (it requieres a timeout in while):
...
while(client.available()>0) {
// Read max buffer data Leaving last byte to convert the buffer to String NULLing last byte.
avail=client.read(&buffer[0], 255);
// Limit received data to 1024 bytes this will avoid flooding and collapsing arduino.
// Enough for HTTP header and command or data but limited.
// It can be removed safely.
while(avail>0 && received<1024) {
received+=avail;
buffer[avail]=0; // Set last char to NULL to terminate String and concat.
data.concat(String((char *)buffer));
avail=client.read(&buffer[0], 255);
}
}.
...
Nope, client.flush() doesn't do anything... in the source:
void GSMClient::flush()
{
}
is empty.
Hum, ok. I guess the way to check these is gsm.isAccessAlive()
and gprs.status()
? I'm finding that the online documentation and even the header documentation are not what I'd expect, and there is no use of these in any of the examples. Checking the GSMClient
status is documented, though.
Thanks for the example for reading chunks into a buffer, that makes an enormous difference.
Hi! Yes I check gsm.isAccessAlive()
, gprs.status()
and also GSMClient::connected()
. No there's any exemple abou that... i fact I'm explaining my own experience.
Right now I'm facing a problem with socket: it connects, but is unable to send data and gprs.status
is connected and gsm.isAccessAlive
returns true. This is a GRPS problem it's solved reattaching... but there's no way to determine the cause and it happens between two and three days. (so it's hard to debug).
When I get an stable version will try to make an example.
Here, if I include the check
if (!gsm.isAccessAlive())
Serial.println(F("gsm access is down!"));
before doing anything else in loop ()
as you said, the sketch goes for a few minutes, then the message gets triggered and everything stops. The past few days the code has been running nonstop without any GSM or GPRS checks in loop ()
, and the server has been getting the data.
Hi @holomorph could you share with us the log and a sketch for reproduce your issue?
Example sketch:
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <MKRGSM.h>
#define PIN "123456"
#define GPRS_APN "foobar"
#define GPRS_LOGIN "user"
#define GPRS_PASSWORD "secret"
#define REQ_FMT \
"POST %s HTTP/1.1\r\n" \
"Host: %s:%d\r\n" \
"X-Session-Id: xxxxxx" \
"Content-Type: application/json\r\n" \
"Content-Length: %d\r\n" \
"\r\n%s"
#define JSON_FMT \
"{\"uid\":\"abcdef\"," \
"\"date\":\"%s\"," \
"\"hp\":%d," \
"\"vibx\":%d," \
"\"viby\":%d," \
"\"pres\":%d," \
"\"temp\":%d," \
"\"session\":\"xxxx\"}"
GSMSSLClient client;
GPRS gprs;
GSM gsm;
static struct tm *timtm;
static uint8_t res[256];
static char buf[1024];
static char json[128];
static char date[128];
static const char *host = "hostname";
static const char *path = "/path/to/resource";
unsigned long then = 0;
const unsigned long period = 1000; // ms
void setup() {
boolean connected = false;
Serial.begin(9600);
while (!connected) {
if ((gsm.begin(PIN) == GSM_READY) &&
(gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY)) {
connected = true;
} else {
Serial.println(F("not connected"));
delay(1000);
}
}
Serial.print(F("connecting to "));
Serial.print(host);
Serial.print(F("..."));
if (client.connect(host, 443))
Serial.println(F("done"));
else
Serial.println(F("failed"));
}
void loop() {
unsigned long now;
int h, vy, vx, p, t;
time_t tim;
if (!gsm.isAccessAlive())
Serial.println(F("gsm access is down!"));
if (!(gprs.status() == GPRS_READY))
Serial.println(F("gprs status is not ready!"));
while (!client.connected()) {
Serial.print(F("connection lost. reconnecting..."));
if (client.connect(host, 443))
Serial.println(F("done"));
else {
Serial.println(F("failed"));
delay(1000);
}
}
while (client.available()) {
client.read(&res[0], 255);
}
now = millis();
if (now - then >= period) {
then = now;
tim = gsm.getTime();
if (!(timtm = gmtime(&tim))) {
perror("gmtime");
exit(EXIT_FAILURE);
}
if (!strftime(date, sizeof(date) - 1, "%D %T", timtm)) {
perror("strftime");
exit(EXIT_FAILURE);
}
h = analogRead(A1);
vy = 0; //analogRead(A2);
vx = analogRead(A3);
p = 0; //analogRead(A4);
t = analogRead(A5);
snprintf(json, sizeof(json), JSON_FMT, date, h, vx, vy, p, t);
snprintf(buf, sizeof(buf), REQ_FMT, path, host, 443, strlen(json), json);
client.print(buf);
}
}
Hi!
I'm sorry for my delay. Well, here I'll post my experience, all i've done to make it work and finally an sketch based on the one that has been working 4 weeks, today stills running, without any reset neither manual nor watchdogged.
I think the code should be improved, like it's said in #27.
I've to say that in my own desperation, I programmed a complete socket server in .NET to connect and control multiple MKR's, That reduced a lot the amount of data to be send/received and all becomes super fast... about 0.3 seconds to communicate... Acting over a relay is like be there and pushing a button. So I don't use a web server, but I guess all I explain here would help anyone uses it.
First of all detected that documentation says there should be 20ms between receiving data from SARA and send any to it... so modified ModemClass::send
in Modem.cpp
:
void ModemClass::send(const char* command)
{
if (_lowPowerMode) {
digitalWrite(_dtrPin, LOW);
delay(5);
}
unsigned long dif=millis()-_uartMillis;
if(dif<20) delay(20-dif);
_uart->println(command);
_uart->flush();
_atCommandState = AT_COMMAND_IDLE;
_ready = 0;
}
and ModemClass::poll
:
void ModemClass::poll()
{
while (_uart->available()) {
char c = _uart->read();
_uartMillis=millis();
if (_debug) {
Serial.write(c);
}
Also downgraded modem speed to 57600. I did this because it becomes more stable. Didn't tried to upgrade again but someday when got time...
Also downloaded the latests SAMD core from arduino even hourly updates.
Here's is the modified library. MKRGSM.zip
Then I tried to improve the code making putting a timeout in all the loops to avoid these infinite and damned loops. Unfortunately this didn't solved the problem: then when a couple of infinite loops should occur SARA came crazy. So, the arduino didn't freezed but SARA wasn't able to do nothing, so... another dead-end-street.
After that, realized that it's SARA that makes arduino fall into the infinite loops not responding when it's supossed to do. Reading SARA docs found that SARA needs its time to update its status and do whatever it has to do... I guess that's why reducing modem speed all seemed to worked at least better.
And changed all my sketch:
Also it's very important to have the right power on Arduino if not SARA will hang it in an infinite loop.
I don't know if I'm right or wrong, but it's working. Here is a sample sketch based on the one it's working. It has some limitations about data received/sent because I don't need too much data but It's easy to adapt.
#include <MKRGSM.h>
#define PINGSM "1234"
#define REMOTEHOST "000.000.000.000"
#define REMOTEPORT 12345
#define GPRSAPN "movistar.es"
#define GPRSLOGIN "movistar"
#define GPRSPASS "movistar"
int timerHeartBeat=0;
int timerToken=0;
int timerCurrent=0;
bool GSMConnected=false;
bool socketConnected=false;
bool isDebug=false;
bool isLowPower=false;
String IMEI;
GPRS gprs;
GSM gsm(isDebug);
GSMModem modem;
GSMClient remoto;
IPAddress LocalIP;
void getIMEI() {
IMEI.reserve(15);
MODEM.send("AT+CGSN");
MODEM.waitForResponse(100, &IMEI);
Serial.print("IMEI: ");
Serial.println(IMEI);
}
bool sendMessage(const String& msg) {
bool retorno = false;
int escrito = 0;
byte buf[256];
int len;
len=msg.length();
if(len>256) len=256;
msg.getBytes(buf, len+1);
escrito=remoto.write((uint8_t *)buf, len);
if(escrito==len) {
retorno = true;
} else {
Serial.print("Write Error: ");
Serial.print(escrito);
Serial.print(" of ");
Serial.println(len);
// Check ERROR with +USOCTL=x, y where x is socket number and y is action:
// with AT+USOCTL=socket, 1 we get error detail
// with AT+USOCTL=socket, 4 we get remote ip and port
// with AT+USOCTL=socket, 11 we get number of bytes not received remotelly
// have we to disconnect GSM?
}
return retorno;
}
bool isConnected() {
return (socketConnected && remoto!=NULL);
}
void disconnected() {
if(socketConnected) {
remoto.stop();
Serial.println("Socket disconnected.");
}
socketConnected=false;
}
void connectGSM() {
int intentos=0;
// When fails sengind a AT+UPSDA=0,3 it works again.
GSMConnected=false;
while (!GSMConnected && intentos<10) {
Serial.write("Inicializando GSM\n");
if (gsm.begin(PINGSM)==GSM_READY) {
Serial.write("Inicializando GPRS\n");
if(gprs.attachGPRS(GPRSAPN, GPRSLOGIN, GPRSPASS)==GPRS_READY) {
GSMConnected = true;
}
} else {
Serial.println("Not connected retrying...");
delay(1000); // Let's Sara Breath...
}
intentos++;
}
if(!GSMConnected) {
Serial.println("Can't initialize, retrying.");
delay(3000); // Let's SARA breath.
// Reboot??
//doReset();
} else {
getIMEI();
LocalIP = gprs.getIPAddress();
Serial.print("IP Address: ");
Serial.println(LocalIP);
}
}
void connectRemote() {
if(!isConnected()) {
Serial.println("Connecting Remote Socket");
if(remoto.connect(REMOTEHOST, REMOTEPORT)==1) {
Serial.println("Socket Connected.");
socketConnected=true;
} else {
Serial.println("Error connecting socket.");
delay(1000); // Let's SARA breath...
MODEM.noop(); // Send AT
delay(1000); // And let's SARA breath again... it will update its internal state. That did the trick!
}
} else {
Serial.println("Remote socket yet connected.");
}
}
void checkAvailable() {
int avail;
int recibido=0;
bool hay=false;
uint8_t buffer[256];
int len;
unsigned long start = millis();
String cadena="";
if(remoto.connected()) {
avail=remoto.available();
while(avail>0) {
if(millis()-start>10000) break;
hay=true;
if(avail>255) avail=255;
avail=remoto.read(&buffer[0], avail);
recibido+=avail;
buffer[avail]=0;
cadena.concat(String((char *)buffer));
avail=remoto.available();
}
if(hay) {
len=cadena.length();
if(len>256) cadena=cadena.substring(len-256); // Only need first 256 chars
Serial.print("Received: ");
Serial.println(cadena);
//parseReceived(); // Parse received data.
}
} else {
disconnected();
}
}
void enterLowPower() {
Serial.println("Enable low power");
MODEM.lowPowerMode();
isLowPower=true;
}
void exitLowPower() {
Serial.println("Exit low power");
MODEM.noLowPowerMode();
isLowPower=false;
}
void sendHeartbeat() {
String msg="";
int currentMillis=millis();
if(remoto.connected()) {
Serial.println("Send Heartbeat");
msg.concat("BOM HELLO WORLD EOM");
if(msg.length()>0) {
Serial.print("Message: ");
Serial.println(msg);
if(sendMessage(msg)) {
Serial.println("Communication OK");
} else {
Serial.println("Error Writing Data...");
disconnected();
}
}
} else {
disconnected();
}
}
void doReset() {
//NVIC_SystemReset(); // Removed to reduce requirements.
while (true);
}
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Persistent Client v0.67");
connectGSM();
}
void loop() {
int currentMillis=millis();
char c;
// Send # or $ though console to enable/disable debug.
while(Serial.available()) {
c=Serial.read();
if(c=='#') {
if(isDebug) {
isDebug=false;
MODEM.noDebug();
Serial.println("Disable DEBUG");
}
} else if(c!='\n' && c!='\r') {
if(!isDebug) {
isDebug=true;
MODEM.debug();
Serial.println("Enable DEBUG");
}
}
//MODEM.write(c);
}
if(isConnected()) {
checkAvailable();
if((currentMillis-timerHeartBeat)>60000 || timerHeartBeat==0) {
// Send every minute.
sendHeartbeat();
timerHeartBeat=currentMillis;
}
} else {
if((currentMillis-timerHeartBeat)>5000) {
// No connection try every 5 seconds. Let's SARA breath again.
if(gsm.isAccessAlive()) {
if(gprs.status()==GPRS_READY) {
connectRemote();
timerHeartBeat=currentMillis;
} else {
// Disconnected...
Serial.println("Connecting GPRS...");
if(gprs.attachGPRS(GPRSAPN, GPRSLOGIN, GPRSPASS)==GPRS_READY) {
connectRemote();
}
}
} else {
connectGSM();
}
}
}
}
Hope it helps!
Hi Franc,
I have an issue with the library and the MKR GSM 1400. I'm using the following code to check if the connection has been done correctly, but looking forward to possible problems (in this case a broken or unscrewed antenna and the impossibility of connecting to the network) the code in question loops and never ends and obviously ends up in an endless loop. ` use_proxy = false;
// start GSM shield // if your SIM has PIN, pass it as a parameter of begin() in quotes Serial.print("Connecting GSM network..."); if (gsmAccess.begin(PINNUMBER) != GSM_READY) { Serial.println(errortext); while (true); } Serial.println(oktext);` There is some way to make X attempts and then else because now else never gets to execute it, because the module is asking for the connection "in eternum".
Thank you very much because I'm very very stuck
Muchas gracias
Eduard
Hi @eduardcabanas !
As @Rocketct said in #36 you should check both GSM and GPRS connection before trying to do something, and take care about current drawn by your power source: without a good antenna SARA will require more current and if your power isn't good enough it will hangs. I think this should be sorted out: if SARA doesn't have enough power it should return an error or hang it self not leave MKR hanged. I'm working on it and will share when done.
For your code I'd encapsulate all in nested if sequence for connection and while for retry:
int i=0;
while(i<3) {
i++;
if (gsmAccess.begin(PINNUMBER) != GSM_READY) {
if(gprsAccess.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY) {
// Do something.
break;
} else {
Serial.println("GPRS Error");
} else {
Serial.println("GSM Error");
}
}
gsmAccess.shutdown();
// Sleep...
Hope it helps!
Hi @FrancMunoz
Thank you for your help, but the problem is not if it's connected, I'm installing this arduino in the middle of a field, and sometimes there we lose roaming due to lack of service or somebody hit the antenna, etc... Now I'm checking all the variants that could happen there, and the first simulation was disconnect the antenna simulating one of these situations that I commented before. That's the problem if you disconnect the antenna, the system enters an infinite loop because he could not connect to the tower. If this happens, the arduino will be dead forever. If I debug the connection, I saw infinite +CREG: 0,0 responses after AT+CREG? callings...
a) is it possible to "count" for example 5 +CREG: 0,0 responses and if this happens shutdown the arduino (I'm using lowpower to put arduino in sleep mode till nexts 15 minutes) b) there is any function in the library to check this +CREG: 0,0 response?
Thank you very very much for yor help
Eduard
Hi @eduardcabanas !
In my case after some +CREG
responses SARA return an error, that's why theGSM.begin()
and GPRS.attachGPRS()
are functions: because both should return the state.
In your case, you should not loose MKR control (well, in fact no one wants that), you have two options here:
GSM.h in private section of the class:
int _processMillis;
GSM.cpp
int GSM::ready()
{
if (_state == ERROR) {
return 2;
}
int ready = MODEM.ready();
if (ready == 0) {
return 0;
}
// CHECK wether begin lasts more than 30 seconds.
if(_readyState!=READY_STATE_CHECK_SIM && _readyState!=READY_STATE_DONE && millis()-_processMillis>30000) {
_state = ERROR;
ready = 2;
return ready;
}
switch (_readyState) {
case READY_STATE_CHECK_SIM: {
_processMillis=millis(); // Set start time.
...
That should be implemented to in GRPS.cpp attaching GPRS in should last a lot too if bad signal from antenna when AT+UPSDA=0,3
is called. Just not lot loose control of MKF.
And the second option:
GSM.begin()
and GRPS.attachGPRS()
. I'm just playing with it right now because I need MRK do some tasks while connecting or when connection is not available.
I prefer this way but control logic is little bit complicated because you have to care the status all the time. As a result the modem only will block MKR when you need to read or send data. When I have it working will try to make PR whith the example.
I would only use asynchronous function in GSM.begin()
and GRPS.attachGPRS()
the rest of calls would use the synced ones that are easier to manage.In your case you could read sensors while MRK is connecting or just save records in an SD card as a datalogger does. So, when all is right you have data in server but when a failure happens you have the log.
Hope it helps!
Hi @FrancMunoz
Thank you for your help. I modified the library as you mentioned, I uploaded the sketch, disconnect the antenna but with the same result See the code and the library modified attached. Could you review what I di is correct or if it works in your? Many many thank's for your patience Regards from Barcelona
Eduard
Hi @eduardcabanas !
I made a MISTAKE!! %&·$!!** ... I apologize. That use to happens to me when I don't read what I write.
Please change:
int GSM::ready()
{
if (_state == ERROR) {
return 2;
}
int ready = MODEM.ready();
if (ready == 0) {
return 0;
}
// CHECK wether begin lasts more than 30 seconds.
if(_readyState!=READY_STATE_CHECK_SIM && _readyState!=READY_STATE_DONE && millis()-_processMillis>30000) {
_state = ERROR;
ready = 2;
return ready;
}
switch (_readyState) {
case READY_STATE_CHECK_SIM: {
_processMillis=millis(); // Set start time.
...
I've updated the previous post... to avoid confusing people.
All in all, this is weird and should be written in a better way... Ah! ten seconds to connect aren't enough give from 30 seconds to a minute...
Hope it helps!
Hi @FrancMunoz
There is an error compiling:
error: 'readyState' was not declared in this scope
Thank's
Hi @eduardcabanas !
Oh.... there's an underscore before readyState... it has to be: _readyState. I updated boths posts above.
Hope this time is right. I apologize for the mistakes... didn't have enough time to test...
Hi @FrancMunoz
Now it works perfectly!! you are the one... 🥇 by the way, what should I write if I would like to do the same in gprs connection?
Thank you very much
Best
Eduard
Hi @eduardcabanas !
I'm happy to know it worked for you. For GPRS we could use the following:
Remember to create private property _processMillis
as we did in GSM.
int GPRS::ready()
{
int ready = MODEM.ready();
if (ready == 0) {
return 0;
}
// CHECK wether begin lasts more than 30 seconds.
if(_state!=GPRS_STATE_ATTACH && _state!=GPRS_STATE_IDLE && millis()-_processMillis>30000) {
_state = GPRS_STATE_IDLE;
_status = ERROR;
return ready;
}
switch (_state) {
case GPRS_STATE_IDLE:
default: {
break;
}
case GPRS_STATE_ATTACH: {
_processMillis=millis(); // Set start time.
MODEM.send("AT+CGATT=1");
...
This code, should work. Remember i'm unable to test. Also GPRS_STATE_ACTIVATE_IP
sends
AT+UPSDA=0,3
that can last a lot up to 3 minutes...
Hi @FrancMunoz
Thank you very much for your help, but I found a problem ;-) I'm using the following sketch to simulate the process powering on and off the led. `///////////////////////////////////////////////////////////////Libraries definition//////////////////////////////////////////////////////
// PIN Number const char PINNUMBER[] = ""; //blank if no pin // APN data: check settings on mobile for sim provider or contact carrier for network settings const char GPRS_APN[] = "internet.easym2m.eu"; const char GPRS_LOGIN[] = ""; const char GPRS_PASSWORD[] = "";
GSMClient client; GPRS gprsAccess; GSM gsmAccess;//(true);
// Various variables used in this Sketch String response = ""; String okmsg = "ok"; String errormsg = "error"; void setup() { delay(3000); pinMode(LED_BUILTIN, OUTPUT); LowPower.attachInterruptWakeup(RTC_ALARM_WAKEUP, dummy, CHANGE); // initialize serial communications and wait for port to open: Serial.begin(9600); } void loop() { digitalWrite(LED_BUILTIN, HIGH); int i = 0; Serial.println(i); while (i < 5) { i++; if (gsmAccess.begin(PINNUMBER) != GSM_READY) { Serial.println("GSM Error"); break; }
else {
Serial.println("GSM OK");
// Attach GPRS and check if it works
if (Serial) Serial.println("Attaching to GPRS with your APN...");
if (gprsAccess.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) != GPRS_READY) {
if (Serial) Serial.println(errormsg);
gsmAccess.shutdown();
} else {
// GPRS successfully attached
if (Serial) Serial.println(okmsg);
}
}
}
digitalWrite(LED_BUILTIN, LOW);
LowPower.sleep(20000);
} void dummy() { volatile int aaa = 0; }`
What's happen? the first cycle it work's, but the following not, the arduino only wakeup switch on the led for approx 2 seconds and goes to sleep
you know why???
Thank's Eduard
Hi @eduardcabanas !
I don't use ArduinoLowPower and can't help you right now: don't have enough time to learn about it.
I would like to help you but I'm only sharing my knowledge and experience and since I don't have it about this library, I mean: the impact in MKRGSM and what to do or its state when it awakes... can't really help you.
A litle thing I would do first is not shutdown modem instead I'd put in low power mode and see after awake. This changes the logic of your sketch but it can be arranged for testing.
Good Luck!
Hi @FrancMunoz
Thank's and sorry to be so bored...but the problem is the same when I put a delay and not a sleep.
the first cycle is ok, but next allways give error....I think the problem could be with the millis and _processtime that are not reset after cycle
Thank's
Hi @FrancMunoz At last, all works perfect, it was my fault, now is working with your library modifications and with low-power library
thank's again
Eduard
Hi @eduardcabanas ,
I'm happy to know you succeeded with your project, congratulations!
Hi @FrancMunoz and @eduardcabanas ,
Thank you for these valuable insights !
I am facing a freeze problem during th eestablishment of a gsm/GPRS connection.
cf. a thread at arduino forum https://forum.arduino.cc/index.php?topic=545464.0
I am now trying to replicate your tests : I modified gsm.h, gsm.cpp, gprs.h and gprs.cpp form mkrgsm lib accordingly.
But the very simple following test code copied from @eduardcabanas hangs at gsmAccess.shutdown();
did I do anything wrong ?
Thanks again !
// PIN Number const char PINNUMBER[] = ""; //blank if no pin // APN data: check settings on mobile for sim provider or contact carrier for network settings const char GPRS_APN[] = "soracom.io"; const char GPRS_LOGIN[] = "sora"; const char GPRS_PASSWORD[] = "sora";
GSMClient client; GPRS gprsAccess; GSM gsmAccess;//(true); // Various variables used in this Sketch String response = ""; String okmsg = "ok"; String errormsg = "error";
void setup() { Serial.begin(9600); }
void loop() {
delay(3000); int i = 0; Serial.println(i); while (i < 5) { i++; if (gsmAccess.begin(PINNUMBER) != GSM_READY) { Serial.println("GSM Error");} // if (gprsAccess.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY) { // // Do something. // break; // } // else { // Serial.println("GPRS Error"); // } else { Serial.println("GSM OK"); }
gsmAccess.shutdown();
// Sleep...
Serial.println(gsmAccess.isAccessAlive());
delay(1000);
} }
Hi @holomorph Try to use my code (following) at the end of the loop you could choos to put the arduino in sleep mode or in delay mode
Let me know if it works
I hope it goes well, you have to change the APN and server address
Best
Eduard
`///////////////////////////////////////////////////////////////Libraries definition//////////////////////////////////////////////////////
// PIN Number const char PINNUMBER[] = ""; //blank if no pin // APN data: check settings on mobile for sim provider or contact carrier for network settings const char GPRS_APN[] = "**.com"; const char GPRS_LOGIN[] = ""; const char GPRS_PASSWORD[] = "";
// get this from the wia dashboard. it should start with d_sk
const char* device_secret_key = "01234567890";
GSMClient client; GPRS gprsAccess; GSM gsmAccess;
// Thebluedots API parameters char server[] = "XXXXXX.com"; char path[] = "/api/v2/gprs"; int port = 80;
HttpClient httpClient = HttpClient(client, server, port); String response; int statusCode = 0; String dataStr; String okmsg = "ok"; String errormsg = "error"; void setup() { delay(3000); pinMode(LED_BUILTIN, OUTPUT); LowPower.attachInterruptWakeup(RTC_ALARM_WAKEUP, dummy, CHANGE); // initialize serial communications and wait for port to open: Serial.begin(9600); } void loop() {
digitalWrite(LED_BUILTIN, HIGH);
if (gsmAccess.begin(PINNUMBER) != GSM_READY) { Serial.println("GSM Error"); }
else { Serial.println("GSM OK"); // Attach GPRS and check if it works if (Serial) Serial.print("Attaching to GPRS with your APN..."); if (gprsAccess.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) != GPRS_READY) { if (Serial) Serial.println(errormsg); gsmAccess.shutdown();
} else {
// GPRS successfully attached
if (Serial) Serial.println(okmsg);
float shttemp = 0;
StaticJsonBuffer<300> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["dot"] = "gsm001";
JsonObject& data = root.createNestedObject("data");
data.set("5", shttemp);
// Generate the JSON string to Serial
root.printTo(Serial);
postToWia(root);
// read the status code and body of the response
statusCode = httpClient.responseStatusCode();
response = httpClient.responseBody();
Serial.print("Status code: ");
Serial.println(statusCode);
Serial.print("Response: ");
Serial.println(response);
}
} digitalWrite(LED_BUILTIN, LOW); // delay(300000); LowPower.sleep(15 * 60000);
} void dummy() { volatile int aaa = 0; } void postToWia(JsonObject& data) { dataStr = ""; data.printTo(dataStr); httpClient.beginRequest(); httpClient.post(path); httpClient.sendHeader("Content-Type", "application/json"); httpClient.sendHeader("Content-Length", data.measureLength()); httpClient.sendHeader("Authorization", "Bearer " + String(device_secret_key)); httpClient.beginBody(); httpClient.print(dataStr); httpClient.endRequest();
}`
Hi @eduardcabanas
Thanks for this sketch.
It seems that this is working if I use the delay option, and not working if I use the sleep option . But this is not an issue for me.
I need now to test if for a project that require 6 months uninterruptible service with periodic reconnexion to GSM network, with a solar panel power supply AND an attached battery
I have encountered 5 freezes during my last 2 month testing campaign and i fear that those freeze are caused by battery that cannot furnish enough current at GSM reconnection, even though my battery never went below 4V
I have noticed during some tests at the workshop that even a with battery 18650 ,1S3P 3.7V 7800mAh showing good voltage >4V , the problem can occur for example if the battery was not charged during several days (But having voltage >4V anyway) . The problem never occurs with new batteries, or batteries that were recently charged with a genuine Charger
I dont know if :
See also my question here : cf. https://forum.arduino.cc/index.php?topic=565177.0
NOTE : I have tried the asynchronous implementation of francmunoz https://github.com/FrancMunoz/MKRGSM/tree/master/src
It is interesting because in case of a problem with the SARA modem, the rest of the board is not frozen....but the modem still is ...
Hi!
I did some modifications to MKRGSM library using timeouts to avoid entering in infinite loops and worked fine but it was so difficult to recover modem. I'm still investigating about that.
Also, I'm still working in the asynchronous implementation to be able to recover when signal is lost or wathever... my main is the loop should never be affected by modem status (like a mobile when looses connectivity). When I got news will post or update PR.
All in all @heligone , you have to be careful with current also, not only voltage... the modem (through MKR) can require up to 150mA if it has bad coverage or defective antenna or no antenna. (I've measured 180mA during few milliseconds with sensors). So, my board without antenna connects GPRS and works (I've very good coverage) but requires more power.
So, If source can't draw enough current for modem it does not reply to AT commands and MKR fall into an infinite loop (the fist part above). Now I'm playing with that... hanging loops and modem recovery to achieve an stable-non-modem-dependent loop.
About your project, I used a 24mAh - 3.7V LiPo from a portable power bank and worked well... but the implementation is not the same as yours, but maybe can help.
Hope it helps.
Oh yes indeed you do help ! a lot :)
I have tested your MKRGSM modifications, where your put a 30sec timeout on the AT+CREG? : indeed, it avoids the infinite loop if you put the board in a faraday cage, remove the antenna or if there is no network available. This is great !
I have also tested your asyncrhonous version . It works fine too, and the main loop does not get affected whenever the connection routine enters a loop. But : the modem still is not accessible... A reboot would be required. i was thinking of 2 solutions :
I completely agree with you about the importance of the current that can be drawn from the battery. In the project I am considering, the mkrGSM1400 is powered by a solar panel , which powers the board and also recharges a battery, which is in also connected in parallel to the board to provide extra current during peaks at GSM connexion time. I Can only monitor its voltage .During a 2 month test run last months, I have been sending GPRS messages every 15 minutes . The board was reset every night to avoid memory leak problems. The battery never went under 4V. Yet the board froze 5 times ... at the times of reconnexion.
That is why I say (just like you) : the standard run of the board should not be affected by modem problems, whether because no network or because the battery cannot provide current for peak of consumption.
With the asynchronous mode : From what I saw in your code, the only piece lacking now with your asynchronous library is the modem recovery part :)
In synchronous mode (with your modifications in MKRGSM) : I dont know how to avoid a freeze in AT+CREG if this freeze happens before the 30 seconds time ou that you implemented. I suspect that this freeze is a hardware problem indeed an cannot be solved programmatically
Thanks again for our insights
@FrancMunoz do you think the latest changes in master and PR #52 make things more stable?
Hi, I want to use MKR 1400 to permanently send data to web server using GSMClient. I want to build real IoT device.
Data from sensor are send as param of GET request. It works well several minutes (even with battery) but I don't know how to recover from fail state (disconnection). Please provide clear and well described example for it as a part of this project (not only in this issue). Current just-one-time request example (GsmWebClient.ino) is useless. Nobody needs to do only one request and exit. Provide better examples to support people when creating real word projects.
@FrancMunoz, thanks for sketch but I don't like it. Methods aren't described, there are unused methods (enterLowPower
, exitLowPower
), confusing names (remoto
, IMEI
, retorno
). Why you write doReset
method as while (true);
?
Sorry, I am angry a little bit because it's very hard to do basic IoT long-term running routine with this stuff.
Hi Josef
I was with your similiar situation and I was angry too, but this is not an end product, it’s a developing product and you have to test, investigate and test again.
The guys who develop things with these devices we spend a lot of months, mails and overall a lot of thank’s
I aim to you to keep pushing and if you don’t understand some words, use google translator that works in these cases
There are a lot of examples in arduino’s forum, there are a lot of examples that you could use, combine and test. I’m sure you will find the solution
Best
Eduard
El 12 oct 2018, a las 0:11, Josef Hák notifications@github.com escribió:
Hi, I want to use MKR 1400 to permanently send data to web server using GSMClient. I want to build real IoT device.
Data from sensor are send as param of GET request. It works well several minutes (even with battery) but I don't know how to recover from fail state (disconnection). Please provide clear and well described example for it as a part of this project (not only in this issue). Current just-one-time request example (GsmWebClient.ino) is useless. Nobody needs to do only one request and exit. Provide better examples to support people when creating real word projects.
@FrancMunoz, thanks for sketch but I don't like it. Methods aren't described, there are unused methods (enterLowPower, exitLowPower), confusing names (remoto, IMEI, retorno). Why you write doReset method as while (true);?
Sorry, I am angry a little bit because it's very hard to do basic IoT long-term running routine with this stuff.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.
I tried writing a program structured like so
However, it appeared
loop()
would only run a small number of times before the program halted. I also had code for checking/re-establishing a connection beforeclient.print(req)
, so a dropped connection was not the problem. I don't know how to introspect the program, so my best guess is an issue with memory. I ended up working around this by keeping theGSMSSLCLient
declaration local withinloop()
, as belowbut this isn't desirable because I'd like the
period
to be less than the time it takes to connect. I realize I can work around this further by keeping collected data in an array and just fire off several HTTP requests each loop, but I can't help but wondering if I'm doing something wrong in the former snippet.