vshymanskyy / TinyGSM

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

performance / timeout issue with 9600 baud rate #23

Closed holgerkoch closed 7 years ago

holgerkoch commented 7 years ago

Hello, i tried really hard and read all issues. But i can't found a solution for my problem. So maybe you can give me a hint.

I try your example code for a mqtt client. If i set the connection speed for the modem to a higher value than 9600, it's working. If a set it to 9600, i get the error:

Initializing modem...
Waiting for network... OK
Connecting to web.vodafone.de OK
Connecting to alpha.holgerkoch.de fail
-4
Connecting to alpha.holgerkoch.de fail
-4

and the Logfile of the mosquitto server:

1491121475: New connection from 109.43.1.92 on port 1883.
1491121475: New client connected from 109.43.1.92 as elnagh (c1, k15, u'wohnmobil').
1491121475: Sending CONNACK to elnagh (0, 0)
1491121491: Socket error on client elnagh, disconnecting.

I use the latest version of pubsub and TinyGSM library. The MQTT Server is

[root@alpha mosquitto]# rpm -qa|grep mosquitto
libmosquitto1-1.4.10-3.1.x86_64
libmosquitto-devel-1.4.10-3.1.x86_64
mosquitto-1.4.10-3.1.x86_64
mosquitto-clients-1.4.10-3.1.x86_64

I tried to raise the timeouts for

#define MQTT_KEEPALIVE 60
#define MQTT_SOCKET_TIMEOUT 60

but it doesn't help. From time to time, maybe once the hour, i got a connection and then it works like a dream.

Can you give me a hint?

Best regards

Holger

/**************************************************************
 *
 * For this example, you need to install PubSubClient library:
 *   https://github.com/knolleary/pubsubclient/releases/latest
 *   or from http://librarymanager/all#PubSubClient
 *
 * TinyGSM Getting Started guide:
 *   http://tiny.cc/tiny-gsm-readme
 *
 **************************************************************
 * Use Mosquitto client tools to work with MQTT
 *   Ubuntu/Linux: sudo apt-get install mosquitto-clients
 *   Windows:      https://mosquitto.org/download/
 *
 * Subscribe for messages:
 *   mosquitto_sub -h test.mosquitto.org -t GsmClientTest/init -t GsmClientTest/ledStatus -q 1
 * Toggle led:
 *   mosquitto_pub -h test.mosquitto.org -t GsmClientTest/led -q 1 -m "toggle"
 *
 * You can use Node-RED for wiring together MQTT-enabled devices
 *   https://nodered.org/
 * Also, take a look at these additional Node-RED modules:
 *   node-red-contrib-blynk-websockets
 *   node-red-dashboard
 *
 **************************************************************/

// Select your modem:
#define TINY_GSM_MODEM_SIM800
//#define TINY_GSM_MODEM_SIM900
//#define TINY_GSM_MODEM_A6
//#define TINY_GSM_MODEM_M590

#include <TinyGsmClient.h>
#include <PubSubClient.h>

// Your GPRS credentials
// Leave empty, if missing user or pass
const char apn[]  = "web.vodafone.de";
const char user[] = "";
const char pass[] = "";

// Use Hardware Serial on Mega, Leonardo, Micro
//#define SerialAT Serial1

// or Software Serial on Uno, Nano
#include <SoftwareSerial.h>
SoftwareSerial SerialAT(5, 4); // RX, TX

TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
PubSubClient mqtt(client);

long lastReconnectAttempt = 0;

void setup() {
  // Set console baud rate
  Serial.begin(9600);
  delay(10);

  // Set GSM module baud rate
  SerialAT.begin(9600);
  delay(3000);

  // Restart takes quite some time
  // To skip it, call init() instead of restart()
  Serial.println("Initializing modem...");
  modem.restart();

  Serial.print("Waiting for network...");
  if (!modem.waitForNetwork()) {
    Serial.println(" fail");
    while (true);
  }
  Serial.println(" OK");

  Serial.print("Connecting to ");
  Serial.print(apn);
  if (!modem.gprsConnect(apn, user, pass)) {
    Serial.println(" fail");
    while (true);
  }
  Serial.println(" OK");

  // MQTT Broker setup
  mqtt.setServer("alpha.holgerkoch.de", 1883);
}

boolean mqttConnect() {
  Serial.print("Connecting to ");
  Serial.print("alpha.holgerkoch.de");
  if (!mqtt.connect("elnagh", "<usernam>", "<password>")) {
    Serial.println(" fail");
    Serial.println(mqtt.state());
    return false;
  }
  Serial.println(" OK");
  mqtt.publish("owntracks/wohnmobil/elnagh", "GsmClientTest started");
  return mqtt.connected();
}

void loop() {

  if (mqtt.connected()) {
    mqtt.loop();
  } else {
    // Reconnect every 10 seconds
    unsigned long t = millis();
    if (t - lastReconnectAttempt > 10000L) {
      lastReconnectAttempt = t;
      if (mqttConnect()) {
        lastReconnectAttempt = 0;
      }
    }
  }
  delay(5000);
  mqtt.publish("owntracks/wohnmobil/elnagh", "Bin drin");

}
GeorgianBorca commented 7 years ago

Hello, The first mistake i see in your code (might not be a big one) is that you have a 5 seconds delay in loop. This delay will block the loop and you won't be able to receive anything in this time. This also might cause a reconnect. Try to use millis() for an interval to publush data.

holgerkoch commented 7 years ago

Hello, 

thank you for your answer. I removed the delay, but it doesn't help. My problem is, that the connect not work:

  if (!mqtt.connect("elnagh", "", "")) {     Serial.println(" fail");     Serial.println(mqtt.state());     return false;   }

Connecting to alpha.holgerkoch.de fail -4

The error code is -4, timeout. But which? I increase both

define MQTT_KEEPALIVE 60

define MQTT_SOCKET_TIMEOUT 60

but it doesn't help. If i increase the serial connection speed to 19200 baud. It works, but only for this example. In my very large project, i still get the timeout.

best regards   Holger Koch  

holgerkoch commented 7 years ago

Hello,

i try your original example for a mqtt client:

https://github.com/vshymanskyy/TinyGSM/tree/master/examples/MqttClient

and make some tests with it. With a serial speed of

SerialAT.begin(115200);

it works nearly always. If you lower the speed, it works only irregular. With a speed of 9600, it works never.

You got a -4, timeout.

Initializing modem... Waiting for network... OK Connecting to web.vodafone.de OK Connecting to test.mosquitto.org fail

Can you tell me, which timeout this means? Is there a possibility to enlarge it?

best regards

Holger

holgerkoch commented 7 years ago

Hello,

i make some further tests with tcpdump and it seems, the network traffic is the same. Whether it works or not.

The state timeout would be set in the "PubSubClient.cpp" line 195, if the client doesn't response in the timeout interval.

        while (!_client->available()) {
            unsigned long t = millis();
            if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) {
                _state = MQTT_CONNECTION_TIMEOUT;
                _client->stop();
                return false;
            }
        }

Please, can you tell me where tinygsm handle the client network connection? Do you have a hint for me, why the communication between the PubSubClient and the TinyGSM library is interrupted?

best regards

Holger

zhoufusong commented 7 years ago

I have the same question, there are any solution now?

holgerkoch commented 7 years ago

No, at the moment there isn't a solution for this problem. I think the problem is the communcation between the pubsubclient and the Client.h In a other library, the pubsubclient is customized for this. Maybe the original can't be stabil for some timing problems. Do you have a ideal for me?

Holger

henkbredell commented 7 years ago

Hello Holger. Thanks for your post. I tried the higher baudrate and this solved the problem for me.

holgerkoch commented 7 years ago

Hello,

Unfortunately this is not a definitive solution. Only the probability that it works will be better. It seems that the client.h simulation for SIM800 is not working perfectly.

Holger

holgerkoch commented 7 years ago

I think, there is somewhere a timeout problem or a race condition. But without help, i can't find the problem.

Holger

vshymanskyy commented 7 years ago

Unfortunately I don't have much time currently to test this, maybe in few weeks...

holgerkoch commented 7 years ago

Thank you for your response. Until you have time for this, can you give me a hint, where to start to analyse?

Best regards

Holger

bsiege commented 7 years ago

9600 with SoftwareSerial has some drawbacks with interrupts and timing.

https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html

AltSoftSerial can tolerate almost 1 bit time latency, so its baud rate must be at least 10 times less than the baud rate used for SoftwareSerial.

Because SoftwareSerial creates 10 bit times of latency for other libraries, it should be used for a device needing high baud rate. SoftwareSerial should NOT be used at slow baud rates, because it will interfere with the other ports.

vshymanskyy commented 7 years ago

Wow @bsiege , thanks for pointing this out! Could anyone check if it really helps? You should be able to use AltSoftSerial with TinyGSM as well.

holgerkoch commented 7 years ago

Unfortunately, i can't test the lib, because i use a wemos. It seems, that the library is only for Arduino Uno:

"Yet another alternate software serial exists for only Arduino Uno, using timer2 and pins 3 and 4. It appears to only work with the ATMEGA328 chip on Uno."

I will try it with the hardware RX/TX, but than i haven't a console log...

Is there another alternative library for wemos?

Best regards Holger

bsiege commented 7 years ago

@holgerkoch Beside from using another optimized SoftwareSerial library. The point is: Try to use as fast as possible/working with any SS, because slower speeds do longer block the system for other subsystems that use interrupts too. Compare with explanations here http://forum.arduino.cc/index.php?topic=206283.0

SoftwareSerial library turns off interrupts during a character transmit, which will severely affect the timing of timer1 interrupts used by Servo library.

And if you need a console log: For mostly sending, this is much less critical with SoftwareSerial (IMHO)

holgerkoch commented 7 years ago

@bsiege, you are right. I try the hardware TX/RX, serial. And it works perfect. Now i make a longterm test and if it works stable, than it is a solution for me. After the program is finished, i don't need the console anymore.

Best regards

Holger

vshymanskyy commented 7 years ago

Thanks guys, I just updated the README to make life easier for others.

psatya111 commented 7 years ago

Hi holgerkoch, I am using a6c gsm module and i have the same timeout problem in below line: while (!_client->available()) { unsigned long t = millis(); if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) { _state = MQTT_CONNECTION_TIMEOUT; _client->stop(); return false; } }

And another problem is that the A6c gsm module is not working in 115200 baud also.could you please help me out. Note :- I am using arduino uno hardware serial(pin:0,1). could you please share me your working code (tinygsm library and mqtt library,and the .ino file.). I need your help.please help me out if possible. my mail id:-psatya111@gmail.com

anibald commented 7 years ago

@psatya111 it was commented around here that SoftwareSerial has some trouble to deal with the necessary latency for the lowest and highest baud rates, you may try to change the modem baud rate and/or change your serial library in favor of AltSoftSerial. You may find a better explanation here: https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html

psatya111 commented 7 years ago

Hi Anibald, Thank you very much for your reply but I am using H/W serial (not software serial) but any way I will try it with different baud rate. and the link you have given is not working(error 404).

Any other approach or help will be appreciated.