shamblett / mqtt_client

A server and browser based MQTT client for dart
Other
548 stars 176 forks source link

mqtt sets reconnection timeout to expire #521

Closed laterdayi closed 6 months ago

laterdayi commented 6 months ago

mqtt sets reconnection timeout to expire ,mqtt_client reconnection timeout did not work

As currently configured, it will always be reconnected without connection timeouts or connection failures, without any ### errors

How can I achieve an error, connection exception or connection timeout if the connection exceeds 5S and be able to catch it

He keeps showing a connection, but the MQTT server is available, but has not been successfully reconnected, and is still connecting

class MqttUtil {

  MqttServerClient? mqttClient;
  MqttQos qos = MqttQos.atLeastOnce;

  static MqttUtil? _instance;
   static MqttUtil getInstance() {
    _instance ??= MqttUtil();
    return _instance!;
  }

  connect({
    String? server,
    int? port,
    String? clientIdentifier,
    String? username,
    String? password,
  }) async {
    try {
      mqttClient = MqttServerClient.withPort(
        AppEnv.kMQTTUrl,
        clientIdentifier ?? 'payton-pda-${UserStore.to.userInfo.user?.id}-${AppStore.to.appInfo.androidId}',
        AppEnv.kMQTTPort,
        maxConnectionAttempts: 1,
      );
      mqttClient?.logging(on: false);
      mqttClient?.keepAlivePeriod = 20;
      mqttClient?.onDisconnected = _onDisconnected;
      mqttClient?.onConnected = _onConnected;
      mqttClient?.onSubscribed = _onSubscribed;
      mqttClient?.onUnsubscribed = _onUnsubscribed;
      mqttClient?.onSubscribeFail = _onSubscribeFail;

      final connMessage = MqttConnectMessage().startClean().withWillQos(MqttQos.exactlyOnce);
      mqttClient?.connectionMessage = connMessage;
      UtilLog.info("connecting");
      return mqttClient?.connect(username, password);
    } catch (e) {
    }
  }

  Subscription? subscribeMessage(String subtopic) {
    return mqttClient?.subscribe(subtopic, qos);
  }

  unsubscribeMessage(String unSubtopic) {
    mqttClient?.unsubscribe(unSubtopic);
  }

  disconnect() {
    mqttClient?.disconnect();
  }
}
shamblett commented 6 months ago

Sorry I'm not understanding you, are you saying you want the client to stop trying to connect after 5 seconds if it doesn't succeed in connecting?

I don't know what this means 'He keeps showing a connection, but the MQTT server is available, but has not been successfully reconnected, and is still connecting'

laterdayi commented 6 months ago

What I mean is that when the server is restarted, the client will try to reconnect, but it will always show the connection, and when the server MQTT is restarted successfully, it will still show the connection and will not reconnect successfully

laterdayi commented 6 months ago

image

laterdayi commented 6 months ago

More than half an hour later, it still shows a connection, no connection timeout, connection error, connection success

shamblett commented 6 months ago

I'll need a client log to see what's going on here, if you have disconnected which I assume you have as you have called on disconnected you have to call connect again to reconnect.

laterdayi commented 6 months ago
I/flutter ( 5325): 1-2024-03-16 20:06:53.158738 -- Authenticating with username '{admin}' and password '{123456}'
I/flutter ( 5325): 1-2024-03-16 20:06:53.160350 -- MqttClient::connect - Connection timeout period is 5000 milliseconds
I/flutter ( 5325): 1-2024-03-16 20:06:53.163210 -- MqttClient::connect - keep alive is enabled with a value of 20 seconds
I/flutter ( 5325): 1-2024-03-16 20:06:53.164160 -- MqttConnectionKeepAlive:: Initialised with a keep alive value of 20 seconds
I/flutter ( 5325): 1-2024-03-16 20:06:53.164309 -- MqttConnectionKeepAlive:: Disconnect on no ping response is disabled
I/flutter ( 5325): 1-2024-03-16 20:06:53.165152 -- MqttConnectionHandlerBase::connect - server 10.100.10.85, port 9012
I/flutter ( 5325): 1-2024-03-16 20:06:53.167143 -- SynchronousMqttServerConnectionHandler::internalConnect entered
I/flutter ( 5325): 1-2024-03-16 20:06:53.167525 -- SynchronousMqttServerConnectionHandler::internalConnect - initiating connection try 0, auto reconnect in progress false
I/flutter ( 5325): 1-2024-03-16 20:06:53.167895 -- SynchronousMqttServerConnectionHandler::internalConnect - insecure TCP selected
I/flutter ( 5325): 1-2024-03-16 20:06:53.168659 -- SynchronousMqttServerConnectionHandler::internalConnect - calling connect
I/flutter ( 5325): 1-2024-03-16 20:06:53.169234 -- MqttNormalConnection::connect - entered
I/flutter ( 5325): 1-2024-03-16 20:07:13.176402 -- MqttConnectionKeepAlive::pingRequired
I/flutter ( 5325): 1-2024-03-16 20:07:13.176824 -- MqttConnectionKeepAlive::pingRequired - NOT sending ping - not connected
I/flutter ( 5325): 1-2024-03-16 20:07:13.176894 -- MqttConnectionKeepAlive::pingRequired - restarting ping timer
laterdayi commented 6 months ago
I/flutter ( 5325): 1-2024-03-16 20:06:53.169234 -- MqttNormalConnection::connect - entered
I/flutter ( 5325): 1-2024-03-16 20:07:13.176402 -- MqttConnectionKeepAlive::pingRequired
I/flutter ( 5325): 1-2024-03-16 20:07:13.176824 -- MqttConnectionKeepAlive::pingRequired - NOT sending ping - not connected
I/flutter ( 5325): 1-2024-03-16 20:07:13.176894 -- MqttConnectionKeepAlive::pingRequired - restarting ping timer
I/flutter ( 5325): 1-2024-03-16 20:07:33.197554 -- MqttConnectionKeepAlive::pingRequired
I/flutter ( 5325): 1-2024-03-16 20:07:33.197792 -- MqttConnectionKeepAlive::pingRequired - NOT sending ping - not connected
I/flutter ( 5325): 1-2024-03-16 20:07:33.197947 -- MqttConnectionKeepAlive::pingRequired - restarting ping timer
laterdayi commented 6 months ago

So far the log has been indicating /// Set the correct MQTT protocol for testing against mosquito, and I have no callback to handle manually disconnecting @shamblett

laterdayi commented 6 months ago

I set up a timeout connection for 5S, and after 5S, there are no exceptions or event callbacks to let me know that the timeout has occurred

shamblett commented 6 months ago

The logs seem incomplete I cant see the sending of a connect message nor receipt of a connect ack.

Could you supply a complete client log of the initial connection and what happens when your MQTT broker disconnects.

laterdayi commented 6 months ago
I/flutter ( 5325): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter ( 5325): │ 21:37:00.466 (+0:00:00.002435)
I/flutter ( 5325): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter ( 5325): │ 💡 HomeController Mqtt -Connecting
I/flutter ( 5325): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter ( 5325): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter ( 5325): │ 21:37:00.480 (+0:00:00.016625)
I/flutter ( 5325): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter ( 5325): │ 💡 Connecting 10.100.10.85
I/flutter ( 5325): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter ( 5325): 1-2024-03-16 21:37:00.491272 -- Authenticating with username '{admin}' and password '{123456}'
I/flutter ( 5325): 1-2024-03-16 21:37:00.492871 -- MqttClient::connect - Connection timeout period is 5000 milliseconds
I/flutter ( 5325): 1-2024-03-16 21:37:00.495914 -- MqttClient::connect - keep alive is enabled with a value of 5 seconds
I/flutter ( 5325): 1-2024-03-16 21:37:00.497245 -- MqttConnectionKeepAlive:: Initialised with a keep alive value of 5 seconds
I/flutter ( 5325): 1-2024-03-16 21:37:00.497523 -- MqttConnectionKeepAlive:: Disconnect on no ping response is enabled with a value of 5000 seconds
I/flutter ( 5325): 1-2024-03-16 21:37:00.498905 -- MqttConnectionHandlerBase::connect - server 10.100.10.85, port 9012
I/flutter ( 5325): 1-2024-03-16 21:37:00.500948 -- SynchronousMqttServerConnectionHandler::internalConnect entered
I/flutter ( 5325): 1-2024-03-16 21:37:00.501209 -- SynchronousMqttServerConnectionHandler::internalConnect - initiating connection try 0, auto reconnect in progress false
I/flutter ( 5325): 1-2024-03-16 21:37:00.501444 -- SynchronousMqttServerConnectionHandler::internalConnect - insecure TCP selected
I/flutter ( 5325): 1-2024-03-16 21:37:00.501955 -- SynchronousMqttServerConnectionHandler::internalConnect - calling connect
I/flutter ( 5325): 1-2024-03-16 21:37:00.502554 -- MqttNormalConnection::connect - entered
I/flutter ( 5325): 1-2024-03-16 21:37:05.501242 -- MqttConnectionKeepAlive::pingRequired
I/flutter ( 5325): 1-2024-03-16 21:37:05.501775 -- MqttConnectionKeepAlive::pingRequired - NOT sending ping - not connected
I/flutter ( 5325): 1-2024-03-16 21:37:05.501947 -- MqttConnectionKeepAlive::pingRequired - restarting ping timer
I/flutter ( 5325): 1-2024-03-16 21:37:05.502098 -- MqttConnectionKeepAlive::pingRequired - starting disconnect timer
I/flutter ( 5325): 1-2024-03-16 21:37:05.502303 -- MqttConnectionKeepAlive::noMessageSent - not disconnecting, not connected
I/flutter ( 5325): 1-2024-03-16 21:37:10.509325 -- MqttConnectionKeepAlive::pingRequired
I/flutter ( 5325): 1-2024-03-16 21:37:10.509615 -- MqttConnectionKeepAlive::pingRequired - NOT sending ping - not connected
I/flutter ( 5325): 1-2024-03-16 21:37:10.509775 -- MqttConnectionKeepAlive::pingRequired - restarting ping timer
I/flutter ( 5325): 1-2024-03-16 21:37:10.510014 -- MqttConnectionKeepAlive::pingRequired - starting disconnect timer
I/flutter ( 5325): 1-2024-03-16 21:37:10.510085 -- MqttConnectionKeepAlive::noMessageSent - not disconnecting, not connected
I/flutter ( 5325): 1-2024-03-16 21:37:15.520063 -- MqttConnectionKeepAlive::pingRequired
I/flutter ( 5325): 1-2024-03-16 21:37:15.520343 -- MqttConnectionKeepAlive::pingRequired - NOT sending ping - not connected

This is my entire log, and it says' NOT sending ping - not connected 'every 5s

What I am wondering now is, I set the timeout connection for 5s, why there is no exception after 5s

laterdayi commented 6 months ago

@shamblett Looking forward to your help

shamblett commented 6 months ago

There is a gap in your logs of 5 seconds from here -

I/flutter ( 5325): 1-2024-03-16 21:37:00.502554 -- MqttNormalConnection::connect - entered

to here

I/flutter ( 5325): 1-2024-03-16 21:37:05.501242 -- MqttConnectionKeepAlive::pingRequired

It looks as though you are not connected but I don't know why, it should show the sending of your connect message as in the example below -

.....
I/flutter ( 3528): 1-2024-03-14 19:20:32.352038 -- MqttNormalConnection::connect - entered
I/flutter ( 3528): --------------------Instance of 'XMqttClient'
I/flutter ( 3528): 1-2024-03-14 19:20:32.482934 -- MqttServerConnection::_startListening
I/flutter ( 3528): 1-2024-03-14 19:20:32.485095 -- SynchronousMqttServerConnectionHandler::internalConnect - connection complete
I/flutter ( 3528): 1-2024-03-14 19:20:32.485327 -- SynchronousMqttServerConnectionHandler::internalConnect sending connect message
I/flutter ( 3528): 1-2024-03-14 19:20:32.486026 -- MqttConnectionHandlerBase::sendMessage - MQTTMessage of type MqttMessageType.connect
I/flutter ( 3528): Header: MessageType = MqttMessageType.connect, Duplicate = false, Retain = false, Qos = MqttQos.atMostOnce, Size = 0
I/flutter ( 3528): Connect Variable Header: ProtocolName=MQIsdp, ProtocolVersion=3, ConnectFlags=Connect Flags: Reserved1=false, CleanStart=true, WillFlag=true, WillQos=MqttQos.atLeastOnce, WillRetain=false, PasswordFlag=true, UserNameFlag=true, KeepAlive=0
.....

Looking at your code above you have this -

 mqttClient?.logging(on: false);

This should be set to true, also you do seem to have an onDisconnected callback -

 mqttClient?.onDisconnected = _onDisconnected;

The calling of this should also be logged, please supply a complete client log.

laterdayi commented 6 months ago

This is already the complete log, MQTT is not connected, the connection time has expired and there are no exceptions or callbacks

laterdayi commented 6 months ago

onDisconnected is not called, MQTT is always connected, with no timeout or exception

laterdayi commented 6 months ago

@shamblett

shamblett commented 6 months ago

This is not a complete log from the MQTT client, please look through the issues for examples of complete logs also you say 'onDisconnected is not called, MQTT is always connected, with no timeout or exception' but your log above is showing its not connected -

I/flutter ( 5325): 1-2024-03-16 21:37:10.509325 -- MqttConnectionKeepAlive::pingRequired
I/flutter ( 5325): 1-2024-03-16 21:37:10.509615 -- MqttConnectionKeepAlive::pingRequired - NOT sending ping - not connected
laterdayi commented 6 months ago

This is indeed all the logs, perhaps because the server is not starting service, but now I can't trigger any callbacks, and after 5S, there are no timeout exceptions

laterdayi commented 6 months ago

https://github.com/shamblett/mqtt_client/assets/122137647/14242626-b5e2-45f3-b18d-78a6d6f97ac9

laterdayi commented 6 months ago

@shamblett

shamblett commented 6 months ago

Sorry uouve lost me completely now, Ive never seen the client skip log entries also This is indeed all the logs, what does this mean 'perhaps because the server is not starting service, but now I can't trigger any callbacks, and after 5S, there are no timeout exceptions' What server? What service?

laterdayi commented 6 months ago

https://github.com/shamblett/mqtt_client/assets/122137647/39e13032-0159-438a-a0a1-7909168c187e

This is all the logs in one minute, and I'll briefly describe the problem I encountered

  1. I set a timeout of five seconds. I hope that after five seconds, I can manually disconnect and reconnect. How should this be achieved?
  2. Now NOT sending ping - not connected will be repeated infinitely in the log. Is there a callback function that can handle it?
  3. What I want is that if the connection is not successful in 5S, I want to manually disconnect and reconnect manually.

Looking forward to your help

@shamblett

laterdayi commented 6 months ago
class MqttUtil {
  // 
  MqttServerClient? mqttClient;
  MqttQos qos = MqttQos.atLeastOnce;
  //
  static MqttUtil? _instance;
  // 
  static MqttUtil getInstance() {
    _instance ??= MqttUtil();
    return _instance!;
  }

  // 
  Future<MqttClientConnectionStatus?> connect({
    String? server,
    int? port,
    String? clientIdentifier,
    String? username,
    String? password,
  }) async {
    try {
      mqttClient = MqttServerClient.withPort(
        AppEnv.kMQTTUrl,
        clientIdentifier ?? 'payton-pda-${UserStore.to.userInfo.user?.id}-${AppStore.to.appInfo.androidId}',
        AppEnv.kMQTTPort,
        maxConnectionAttempts: 1,
      );
      mqttClient?.logging(on: true);
      mqttClient?.keepAlivePeriod = 3;
      mqttClient?.onDisconnected = _onDisconnected;
      mqttClient?.onConnected = _onConnected;
      mqttClient?.onSubscribed = _onSubscribed;
      mqttClient?.onUnsubscribed = _onUnsubscribed;
      mqttClient?.onSubscribeFail = _onSubscribeFail;
      mqttClient?.pongCallback = () {
        UtilLog.info('pongCallback1111');
      };
      mqttClient?.connectTimeoutPeriod = 3000;
      mqttClient?.disconnectOnNoResponsePeriod = 3000;

      mqttClient?.onBadCertificate = (x) {
        UtilLog.info('onBadCertificate');
        return false;
      };
      mqttClient?.onAutoReconnected = () {
        UtilLog.info('onAutoReconnected');
      };
      mqttClient?.onAutoReconnect = () {
        UtilLog.info('onAutoReconnectComplete');
      };

      final connMessage = MqttConnectMessage().startClean().withWillQos(MqttQos.exactlyOnce);
      mqttClient?.connectionMessage = connMessage;
      UtilLog.info("Connecting ${AppEnv.kMQTTUrl}");
      return mqttClient?.connect(username, password);
    } catch (e) {
      UtilLog.error('MqttUtil connect', e);
    }
    return null;
  }

  // 
  Subscription? subscribeMessage(String subtopic) {
    return mqttClient?.subscribe(subtopic, qos);
  }

  unsubscribeMessage(String unSubtopic) {
    mqttClient?.unsubscribe(unSubtopic);
  }
  disconnect() {
    mqttClient?.disconnect();
  }
}
  connectMqtt() async {
    try {
      if (MqttUtil.getInstance().getMqttStatus() == MqttConnectionState.connected) {
        UtilLog.info('');
        MqttUtil.getInstance().subscribeMessage(Topics.awaitTakeOver);
      } else {
        UtilLog.info('HomeController Mqtt -Connecting');
        MqttClientConnectionStatus? status = await MqttUtil.getInstance().connect(
          username: 'admin',
          password: '123456',
        );
        connectMqtt();
        print(status);
      }
    } on Exception catch (e) {
      // 
      print(': $e');
    } on ConnectionException catch (e, s) {
      print(':$e');
    } on NoConnectionException catch (e, s) {
      print(':$e');
    } on SocketException catch (e, s) {
      print('Socket: $e');
    } catch (e, s) {
      print(':$e');
    }
    if (MqttUtil.getInstance().getMqttStatus() != MqttConnectionState.connected) {
      // MqttUtil.getInstance().disconnect();
    }
  }
shamblett commented 6 months ago

I can't see anywhere above where you set a timer for 5 seconds, however what I think you need to do is -

You have mqttClient?.connectTimeoutPeriod = 3000;, set this to 1000

You have maxConnectionAttempts 1, set this to 5

This will give you 5 connection attempts each 1 second apart, if the client is not connected after this period it will stop trying, giving you your 5 seconds, after that you can do your manual disconnect etc. You wont get an onDisconnected callback.

laterdayi commented 6 months ago

My understanding is that I set connectTimeoutPeriod = 3000. After more than 3S, mqtt_clicnt will help me disconnect and throw a timeout exception.

Do I now need to customize a timer to manually close the connection?

@shamblett

shamblett commented 6 months ago

Does the API documents say the client throws an exception after any kind of timeout? I don't think it does. Your understanding is wrong, please read the API docs.

You can start as many timers as you wish and do with them what you wish, anything that happens outside the client is not really of concern to this package.

Please identify any bugs you find or feature you want on added on the client, this is not a general purpose forum for how to handle MQTT clients.

laterdayi commented 6 months ago

If you want to add a callback or function when the connection times out, mqtt_client can throw a timeout exception.

shamblett commented 6 months ago

OK, so are you asking for a callback to be added in between connection attempts, i.e. if maxConnectionAttempts is 5 then you will trigger the callback on each failed connection attempt. If that's the case raise an issue for this documenting exactly what you want and which use case this will help with and I'll mark it as a feature request.

laterdayi commented 6 months ago

@shamblett https://github.com/shamblett/mqtt_client/issues/523 added a new request, describing the functionality and usage, looking forward to adding it, very urgent, thank you for the great work

shamblett commented 6 months ago

OK, closing this moving the work to #523