vshymanskyy / TinyGSM

A small Arduino library for GSM modules, that just works
GNU Lesser General Public License v3.0
1.91k stars 708 forks source link

Http connection error after some time. SIM7000G #629

Open Tonisg91 opened 2 years ago

Tonisg91 commented 2 years ago

Hi all. I am doing some tests with an ESP32 Lilygo TTGO SIM7000 and I have warned that there is a problem with HTTP after some time sending data.

When you turn on the ESP32 it works correctly and after about an hour of sending data, the connection fails and it does not connect again.

This is the code. Any suggestion?

#define SerialMon Serial

// Set serial for AT commands (to the module)`
// Use Hardware Serial on Mega, Leonardo, Micro
#define SerialAT Serial1

#define TINY_GSM_MODEM_SIM7000
#define TINY_GSM_RX_BUFFER 1024 // Set RX buffer to 1Kb

// See all AT commands, if wanted
// #define DUMP_AT_COMMANDS

// set GSM PIN, if any
#define GSM_PIN "XXXX"

// Your GPRS credentials, if any
const char apn[] = "datos";
const char gprsUser[] = "";
const char gprsPass[] = "";

const char server[] = "xxxxxxxxxxx.xxx";
const char coords[] = "/coords";
const int port = 80;

#include <TinyGsmClient.h>
#include <ArduinoHttpClient.h>
#include <ArduinoJson.h>

#define DUMP_AT_COMMANDS

#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
#else
TinyGsm modem(SerialAT);
#endif

TinyGsmClient client(modem);
HttpClient http(client, server, port);

#define uS_TO_S_FACTOR 1000000ULL // Conversion factor for micro seconds to seconds
#define TIME_TO_SLEEP 60          // Time ESP32 will go to sleep (in seconds)

#define UART_BAUD 115200
#define PIN_DTR 25
#define PIN_TX 27
#define PIN_RX 26
#define PWR_PIN 4

#define SD_MISO 2
#define SD_MOSI 15
#define SD_SCLK 14
#define SD_CS 13
#define LED_PIN 12

void modemPowerOn()
{
  pinMode(PWR_PIN, OUTPUT);
  digitalWrite(PWR_PIN, LOW);
  delay(1000); //Datasheet Ton mintues = 1S
  digitalWrite(PWR_PIN, HIGH);
}

void modemPowerOff()
{
  pinMode(PWR_PIN, OUTPUT);
  digitalWrite(PWR_PIN, LOW);
  delay(1500); //Datasheet Ton mintues = 1.2S
  digitalWrite(PWR_PIN, HIGH);
}

void modemRestart()
{
  modemPowerOff();
  delay(1000);
  modemPowerOn();
}

void enableGPS(void)
{
  // Set SIM7000G GPIO4 LOW ,turn on GPS power
  // CMD:AT+SGPIO=0,4,1,1
  // Only in version 20200415 is there a function to control GPS power
  Serial.println("Start positioning . Make sure to locate outdoors.");
  Serial.println("The blue indicator light flashes to indicate positioning.");
  modem.sendAT("+SGPIO=0,4,1,1");
  if (modem.waitResponse(10000L) != 1)
  {
    DBG(" SGPIO=0,4,1,1 false ");
  }
  modem.enableGPS();
}

void disableGPS(void)
{
  // Set SIM7000G GPIO4 LOW ,turn off GPS power
  // CMD:AT+SGPIO=0,4,1,0
  // Only in version 20200415 is there a function to control GPS power
  modem.sendAT("+SGPIO=0,4,1,0");
  if (modem.waitResponse(10000L) != 1)
  {
    DBG(" SGPIO=0,4,1,0 false ");
  }
  modem.disableGPS();
}

void sendCoords(float lat, float lon)
{

  // Prepare JSON document
  StaticJsonDocument<200> doc;
  doc["lat"] = lat;
  doc["lon"] = lon;

  // Serialize JSON document
  String json;
  serializeJson(doc, json);

  int err = http.post(coords, "application/json", json);
  if (err != 0)
  {
    SerialMon.println(F("failed to connect"));
    delay(10000);
    return;
  }

  int status = http.responseStatusCode();

  if (!status)
  {
    delay(10000);
    return;
  }

  String body = http.responseBody();
  SerialMon.println(F("Response:"));
  SerialMon.println(body);

  // Shutdown
  http.stop();
  SerialMon.println(F("Server disconnected"));
}

void setup()
{
  // Set console baud rate
  SerialMon.begin(115200);

  delay(10);

  // Set LED OFF
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);

  SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX);

  delay(10000);

  modemPowerOn();

  Serial.println("Initializing modem...");
  if (!modem.restart())
  {
    Serial.println("Failed to restart modem, attempting to continue without restarting");
  }

  // String modemInfo = modem.getModemInfo();
  // SerialMon.print("Modem Info: ");
  // SerialMon.println(modemInfo);

  // Unlock your SIM card with a PIN if needed
  if (GSM_PIN && modem.getSimStatus() != 3)
  {
    modem.simUnlock(GSM_PIN);
  }
}

void loop()
{

  // GPRS connection parameters are usually set after network registration
  SerialMon.print(F("Connecting to "));
  SerialMon.print(apn);
  if (!modem.gprsConnect(apn, gprsUser, gprsPass))
  {
    SerialMon.println(" fail");
    delay(10000);
    return;
  }
  SerialMon.println(" success");

  if (modem.isGprsConnected())
  {
    SerialMon.println("GPRS connected");
  }

  enableGPS();

  float lat, lon;
  while (1)
  {
    if (modem.getGPS(&lat, &lon))
    {
      sendCoords(lat, lon);
    }
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
    delay(7500);
  }
}

Successful http request AT dump commands.

10:23:58.141 -> 0, CONNECT OK
10:23:58.141 -> AT+CIPSEND=0,4
10:23:58.141 -> 
10:23:58.141 -> >POST 
10:23:58.141 -> DATA ACCEPT:0,4
10:23:58.141 -> AT+CIPSEND=0,1
10:23:58.141 -> 
10:23:58.141 -> DATA ACCEPT:0,1
10:23:58.141 -> AT+CIPSEND=0,7
10:23:58.141 -> 
10:23:58.141 -> >/coords 
10:23:58.174 -> DATA ACCEPT:0,7
10:23:58.174 -> AT+CIPSEND=0,9
10:23:58.174 -> 
10:23:58.174 -> > HTTP/1.1 
10:23:58.174 -> DATA ACCEPT:0,9
10:23:58.174 -> AT+CIPSEND=0,2
10:23:58.174 -> 
 10:23:58.174 -> DATA ACCEPT:0,2
10:23:58.174 -> AT+CIPSEND=0,6
10:23:58.174 -> 
10:23:58.174 -> >Host:  
10:23:58.174 -> DATA ACCEPT:0,6
10:23:58.174 -> AT+CIPSEND=0,24
10:23:58.174 -> 
10:23:58.174 -> >xxx.xxxx.com 
10:23:58.174 -> DATA ACCEPT:0,24
10:23:58.174 -> AT+CIPSEND=0,2
10:23:58.174 -> 
10:23:58.174 -> DATA ACCEPT:0,2
10:23:58.207 -> AT+CIPSEND=0,10
10:23:58.207 -> 
10:23:58.207 -> >User-Agent 
10:23:58.207 -> DATA ACCEPT:0,10
10:23:58.207 -> AT+CIPSEND=0,2
10:23:58.207 -> 
10:23:58.207 -> DATA ACCEPT:0,2
10:23:58.207 -> AT+CIPSEND=0,13
10:23:58.207 -> 
10:23:58.207 -> >Arduino/2.2.0 
10:23:58.207 -> DATA ACCEPT:0,13
10:23:58.207 -> AT+CIPSEND=0,2
10:23:58.207 -> 
10:23:58.207 -> DATA ACCEPT:0,2
10:23:58.207 -> AT+CIPSEND=0,10
10:23:58.207 -> 
10:23:58.207 -> >Connection 
10:23:58.207 -> DATA ACCEPT:0,10
10:23:58.207 -> AT+CIPSEND=0,2
10:23:58.207 -> 
10:23:58.241 -> DATA ACCEPT:0,2
10:23:58.241 -> AT+CIPSEND=0,5
10:23:58.241 -> 
10:23:58.241 -> >close 
10:23:58.241 -> DATA ACCEPT:0,5
10:23:58.241 -> AT+CIPSEND=0,2
10:23:58.241 ->  
10:23:58.241 -> DATA ACCEPT:0,2
10:23:58.241 -> AT+CIPSEND=0,12
10:23:58.241 -> 
10:23:58.241 -> >Content-Type 
10:23:58.241 -> DATA ACCEPT:0,12
10:23:58.241 -> AT+CIPSEND=0,2
10:23:58.241 -> 
10:23:58.241 -> DATA ACCEPT:0,2
10:23:58.241 -> AT+CIPSEND=0,16
10:23:58.241 -> 
10:23:58.241 -> >application/json 
10:23:58.241 -> DATA ACCEPT:0,16
10:23:58.241 -> AT+CIPSEND=0,2
10:23:58.274 ->  
10:23:58.274 -> DATA ACCEPT:0,2
10:23:58.274 -> AT+CIPSEND=0,14
10:23:58.274 -> 
10:23:58.274 -> >Content-Length 
10:23:58.274 -> DATA ACCEPT:0,14
10:23:58.274 -> AT+CIPSEND=0,2
10:23:58.274 ->   
10:23:58.274 -> DATA ACCEPT:0,2
10:23:58.274 -> AT+CIPSEND=0,2
10:23:58.274 -> 
10:23:58.274 -> >31 
10:23:58.274 -> DATA ACCEPT:0,2
10:23:58.274 -> AT+CIPSEND=0,2
10:23:58.274 ->  
10:23:58.274 -> DATA ACCEPT:0,2
10:23:58.274 -> AT+CIPSEND=0,2
10:23:58.274 -> 
10:23:58.307 -> DATA ACCEPT:0,2
10:23:58.307 -> AT+CIPSEND=0,31
10:23:58.307 -> 
10:23:58.307 -> >{"lat":XX.XXXXX,"lon":X.XXXXXX} 
10:23:58.307 -> DATA ACCEPT:0,31
10:23:58.307 -> AT+CIPRXGET=4,0
10:23:58.307 -> 
10:23:58.307 -> +CIPRXGET: 4,0,0
10:23:58.307 -> 
10:23:58.307 -> OK
10:23:58.307 -> AT+CIPSTATUS=0
10:23:58.307 -> 
10:23:58.307 -> +CIPSTATUS: 0,0,"TCP","XX.XXX.XXX.XX","80","CONNECTED"
10:23:58.307 -> 
10:23:58.307 -> OK
10:23:59.308 -> AT+CIPRXGET=4,0
10:23:59.308 -> 
10:23:59.308 -> +CIPRXGET: 1,0
10:23:59.308 -> 
10:23:59.308 -> +CIPRXGET: 4,0,126
10:23:59.308 -> 
10:23:59.308 -> OK
10:23:59.308 -> AT+CIPSTATUS=0
10:23:59.308 -> 
10:23:59.308 -> +CIPSTATUS: 0,0,"TCP","XX.XXX.XXX.XX","80","REMOTE CLOSING"
10:23:59.341 -> 
10:23:59.341 -> OK
10:24:00.341 -> AT+CIPRXGET=4,0
10:24:00.341 -> 
10:24:00.341 -> +CIPRXGET: 4,0,126
10:24:00.341 -> 
10:24:00.341 -> OK
10:24:00.341 -> AT+CIPRXGET=2,0,126
10:24:00.341 -> 
10:24:00.341 -> +CIPRXGET: 2,0,126,0
10:24:00.341 -> HTTP/1.1 200 OK
10:24:00.341 -> Server: Cowboy
10:24:00.341 -> Connection: close
10:24:00.341 -> Content-Length: 0
10:24:00.341 -> Date: Tue, 28 Dec 2021 09:23:58 GMT
10:24:00.341 -> Via: 1.1 vegur
10:24:00.341 -> 
10:24:00.341 -> OK
10:24:00.341 -> Response:
10:24:00.374 -> 
10:24:00.374 -> AT+CIPCLOSE=0
10:24:00.374 -> 
10:24:00.374 -> 0, CLOSE OK
10:24:00.374 -> Server disconnected

Error AT Commands

10:24:53.596 -> AT+CGNSINF
10:24:53.629 -> 
10:24:53.629 -> +CGNSINF: xxxxxxxxxxxxx
10:24:53.629 -> 
10:24:53.629 -> OK
10:24:53.629 -> AT+CIPCLOSE=0
10:24:53.629 -> 
10:24:53.629 -> ERROR
10:24:53.629 -> AT+CIPSTART=0,"TCP","xxxx.xxxxx.com",80
10:24:53.629 -> 
10:24:53.629 -> ERROR
10:24:53.629 -> failed to connect
star297 commented 2 years ago

You are sending GNSS data every 7.5 seconds? That's rather a lot unless moving fast. Does it start working again after a power cycle reset? What exactly is the device you're using and how are you powering it?

Tonisg91 commented 2 years ago

You are sending GNSS data every 7.5 seconds? That's rather a lot unless moving fast. Does it start working again after a power cycle reset? What exactly is the device you're using and how are you powering it?

In the sample code it is 7.5 seconds in effect. At the moment they are just tests.

With an interval of 30s, the same thing happens but the failure comes later. I was planning to send the coordinates only if the change is greater than a certain range (not done yet).

If I restart the device it works correctly.

The device is a Lilygo TTGO SIM7000.

star297 commented 2 years ago

If it restarts then you may have power supply instability problems if you are not using the battery. But its also good practise, well essential tbh, to regularly check your gprs connection, it can drop out for many reasons. Use something like this in your loop, every few minutes or just before sending data:

if (!modem.isGprsConnected()) {
      // run a reconnect function here.
    }

There's a constant battle to keep these things connected to the cell particularly if you are moving around. If you can try to use MQTT rather than HTTP, you will reduce your data. The SIM7000 does work really good using this library and PUBSUB client.

For updating, here's some tips. Distance calculation worked for me, I was using only speed. But you need to allow for drift too so I use a speed/distance combination, if above a certain speed (2 kph works), add the distance.

This will calculate distance:

float geodistance(float lon1, float lat1, float lon2, float lat2)
{
  double R = 6371; // km
  double sLat1 = sin(radians(lat1));
  double sLat2 = sin(radians(lat2));
  double cLat1 = cos(radians(lat1));
  double cLat2 = cos(radians(lat2));
  double cLon  = cos(radians(lon1) - radians(lon2));
  double cosD = sLat1 * sLat2 + cLat1 * cLat2 * cLon;
  double d = acos(cosD);
  double dist = R * d;
  float distf = (float)dist;
  return distf;
}

Call it with this for distance in kilometers, you need current and previous GPS coordinate's.

float track_point_distance = geodistance(GPSlongitude, GPSlatitude,  lastGPSlongitude,  lastGPSlatitude);

You will be surprised how accurate this is, I use it to a meter resolution. Get GPS every second get the distance and keep adding until you ready to send.

Tonisg91 commented 2 years ago

Si se reinicia, es posible que tenga problemas de inestabilidad de la fuente de alimentación si no está usando la batería. Pero también es una buena práctica, bien esencial, por cierto, verificar regularmente su conexión gprs, puede fallar por muchas razones. Use algo como esto en su ciclo, cada pocos minutos o justo antes de enviar datos:

if (!modem.isGprsConnected()) {
      // run a reconnect function here.
    }

Hay una batalla constante para mantener estas cosas conectadas a la celda, especialmente si se está moviendo. Si puede intentar utilizar MQTT en lugar de HTTP, reducirá sus datos. El SIM7000 funciona muy bien con esta biblioteca y el cliente PUBSUB.

Para actualizar, aquí hay algunos consejos. El cálculo de la distancia funcionó para mí, estaba usando solo la velocidad. Pero también debe permitir la deriva, así que utilizo una combinación de velocidad / distancia, si está por encima de cierta velocidad (2 kph funciona), agregue la distancia.

Esto calculará la distancia:

float geodistance(float lon1, float lat1, float lon2, float lat2)
{
  double R = 6371; // km
  double sLat1 = sin(radians(lat1));
  double sLat2 = sin(radians(lat2));
  double cLat1 = cos(radians(lat1));
  double cLat2 = cos(radians(lat2));
  double cLon  = cos(radians(lon1) - radians(lon2));
  double cosD = sLat1 * sLat2 + cLat1 * cLat2 * cLon;
  double d = acos(cosD);
  double dist = R * d;
  float distf = (float)dist;
  return distf;
}

Llámelo con esto para la distancia en kilómetros, necesita coordenadas GPS actuales y anteriores.

float track_point_distance = geodistance(GPSlongitude, GPSlatitude,  lastGPSlongitude,  lastGPSlatitude);

Se sorprenderá de lo preciso que es, lo uso con una resolución de medidor. Obtenga GPS cada segundo, obtenga la distancia y siga agregando hasta que esté listo para enviar.

Hello! I finally went over to mqtt protocol and was able to get it to work stably. At the beginning there were connection problems in about 30% of the data sendings but it already works correctly. Thank you very much for your help, it has been very useful and I have learned things. Greetings and happy new year!

MATDV-117 commented 7 months ago

@Tonisg91 How did you solve it?