shamblett / mqtt_client

A server and browser based MQTT client for dart
Other
552 stars 179 forks source link

Client connectionStatus is not updated properly #476

Closed iosephmagno closed 1 year ago

iosephmagno commented 1 year ago

CC: @shamblett hope you don't mind me mentioning, but I'd really appreciate if you could help with this.

client.connectionStatus!.state returns wrong value when user turns off Internet connection.

To reproduce issue:

1) Connect to broker over cellular data (wifi should be off) 2) Turn off cellular data from device Internet setting

Result:

client.connectionStatus!.state keeps returning MqttConnectionState.connected

Expected Result:

Client shouldn't be able to reach the broker and connectionStatus should be set to MqttConnectionState.disconnected or maybe MqttConnectReturnCode.noneSpecified.

Tested with v. 10.0.0 and 9.8.1 on ios 16.1, android 12 and android 13.

shamblett commented 1 year ago

OK, when you execute step 2 do you get an onDisconnected callback? If you haven't hooked this up in your code please do so.

If you are calling this callback please supply a log of what happens when its called.

If its not called then the runtime is not signalling to the client that a disconnect to the broker has occurred, the client can't do much about this.

iosephmagno commented 1 year ago

Thx! Yes, we call the callback.

Here is the code

Future<void> connect({
    required String clientId,
    required String userid,
  }) async {
    client.port = AppConfig.mqttport;
    client.logging(on: loggerOn);
    client.keepAlivePeriod = 1200;
    client.onConnected = onConnected;
    client.onDisconnected = onDisconnected;
    client.secure = false; //true for secure connection
    client.autoReconnect = true; //true to automatically reconnect
    client.onSubscribed = onSubscribed;
    client.onAutoReconnect = onAutoReconnect;
    client.onUnsubscribed = onUnSubscribed;
    client.resubscribeOnAutoReconnect = true;
    client.disconnectOnNoResponsePeriod = 1; //1 second
    client.manuallyAcknowledgeQos1 = false;

....

  void onDisconnected() {
    debugPrint('Disconnected from MQTT Server server');
  }

LOGS

It looks like onDisconnected is not invoked.

flutter: MQTT isConnected: true
flutter: MQTT client.connectionStatus!.state: MqttConnectionState.connected

Question: even if flutter doesnt signal the disconnection, can't we just grab the event of client not receiving messages from server and therefore set state to MqttConnectionState.disconnected?

iosephmagno commented 1 year ago

Just noticed we can workaround the issue with this package coz it gives a precise status about internet connection. https://pub.dev/packages/observe_internet_connectivity

 InternetConnectivity()
        .observeInternetConnection
        .listen((bool hasInternetAccess) async {
...

But it seems a waste of resources to have a separate socket doing this job while we already have the mqtt connection. I would prefer getting mqtt connection status. If it is connected then internet connection is ON, else we lookupWebsite() to rule out a false positive (mqtt client might be disconnected but internet might be ON). This way we would use only mqtt.

shamblett commented 1 year ago

I see from your code above you have keep alive enabled but you are not setting a disconnect period so the client will not disconnect you. Have a look at this parameter disconnectOnNoResponsePeriod in the client API, set this to say 5 for 5 seconds or whatever you prefer, when the client sees that no ping responses have been received from the broker for this period it will disconnect you.

iosephmagno commented 1 year ago

Thx Steve, we will add it and revert CC: @josh4500

shamblett commented 1 year ago

Just noticed you also have autoReconnect set, so you won't get onDisconnected, you'll get onAutoReconnect instead. You should then stay in autoreconnect until re connection is achieved, if you want to control this manually through onDisconnect then turn off autoreconnect.

Either way your connected status should now be correct.

josh4500 commented 1 year ago

@shamblett Connection status doesn't change if client is disconnected (after a connection was previously made). For now we do not rely on MQTT connection status.

shamblett commented 1 year ago

If this is the case it sounds wrong, I'll need a log showing whats happening when disconnect occurs.

josh4500 commented 1 year ago

Seems to work here on isolation You can check here https://github.com/josh4500/mqtt_connection_test

GradySain commented 1 year ago

I am very new to flutter / dart and this package, but I am experiencing a similar issue. I am using autoReconnect, and that functionality works. I am building a flutter windows desktop app. I launch my broker (shiftr.io desktop), then launch my app, it connects. I shut down broker, client disconnects, restart broker, and client reconnects, no problem. I am using a FutureBuilder like so:

FutureBuilder<MqttServerClient>(
              future: connect(),
              builder: (BuildContext context,
                  AsyncSnapshot<MqttServerClient> snapshot) {
                if (snapshot.connectionState == ConnectionState.waiting) {
                  // If the Future is still running, return a loading indicator
                  return CircularProgressIndicator();
                } else if (snapshot.hasError) {
                  // If we run into an error, display it to the user
                  return Text('Error: ${snapshot.error}');
                } else if (snapshot.data == null) {
                  // Guard against null data
                  return Text('No Data');
                } else {
                  // If the Future is complete and no errors occurred,
                  // check the connection status of the MQTT client

                  MqttConnectionState? state =
                      snapshot.data!.connectionStatus?.state;

                  if (state == MqttConnectionState.connected) {
                    return Text('Connected to MQTT Server');
                  } else if (state == MqttConnectionState.disconnected) {
                    return Text('Disconnected from MQTT Server');
                  } else {
                    // Handle other states or scenarios as required
                    return Text('Unknown State: $state');
                  }
                }
              },
            ),

I would expect the state == MqttConnectionState.disconnected to update... debug console looks like this:

flutter: 1-2023-08-16 10:45:41.048090 -- MqttConnectionBase::_onDone - calling disconnected callback
flutter: 1-2023-08-16 10:45:41.049090 -- MqttConnectionHandlerBase::autoReconnect entered
flutter: EXAMPLE::onAutoReconnect client callback - Client auto reconnection sequence will start
flutter: 1-2023-08-16 10:45:41.050089 -- MqttConnectionHandlerBase::autoReconnect - attempting reconnection

Like I said I'm very new, hopefully this either helps or someone can point out my error... thanks!

GradySain commented 1 year ago

taking a look at @josh4500 code above, trying locally...

GradySain commented 1 year ago

okay @josh4500 thank you- I just learned about ValueNotifiers in Flutter and my code now works. Thanks very much for your example!