0

I'm new in flutter/dart. I'm try to publish a Message via MQTT but still get Unhandled Exception: mqtt-client::ConnectionException: The connection must be in the Connected state in order to perform this operation. error.

The connection to the MQTT Server works. Also I can subscribe to a topic and get continuously the messages.

If I call the publish method with a Button Widget, I get the exception.

I don't understand why listen at subscribe topics work but publish not. Do I need websocket connection ?

Sorry for my english :)

import 'package:mqtt_client/mqtt_client.dart';
import 'package:mqtt_client/mqtt_server_client.dart';
import 'package:untitled/mqtt/MqttNotifier.dart';

class MqttManager
{
  late MqttNotifier _notifier;
  late String _identifier;
  late String _host;
  late String _topic;
  bool waitForConnection = false;
  late MqttServerClient client;

  MqttManager(String host,String topic,String identifier,MqttNotifier notifier)
  {
    _host = host;
    _topic = topic;
    _identifier = identifier;
    _notifier = notifier;
    InitMqttClient();
  }
  void InitMqttClient()
  {
    client = MqttServerClient.withPort('${_host}', '${_identifier}', 1883);
    client.logging(on: true);
    client.onConnected = onConnected;
    client.onDisconnected = onDisconnected;
    client.onSubscribed = onSubscribed;
    client.keepAlivePeriod = 20;

    final connMessage = MqttConnectMessage()
        .withWillQos(MqttQos.exactlyOnce)
        .startClean();
    client.connectionMessage = connMessage;

  }
  void onSubscribed(String topic)
  {
    print("Subscribed to Topic ${topic}");
  }

  void connect() async
  {
    assert(client != null);
    try {
      if(_notifier.GetCurrentConnectionState == ConnectionState.connected)
      {
        client.disconnect();
      }
      else
      {
        await client.connect();
        _notifier.SetConnectionState(ConnectionState.connected);
        _notifier.SetBtnConnectionActivity(BtnConnectionActivity.disconnect);
        subscribe();
      }

    } catch (e) {
      _notifier.SetConnectionState(ConnectionState.disconnected);
      print('Exception: $e');
      client.disconnect();
    }
  }

  void onConnected()
  {
    client.updates!.listen((List<MqttReceivedMessage<MqttMessage?>>? c) {
      final recMess = c![0].payload as MqttPublishMessage;
      String recivedMessage = MqttEncoding().decode(recMess.payload.message);
      _notifier.AddRecivedMessage(recivedMessage);
    });
  }
  void onDisconnected()
  {
    _notifier.SetConnectionState(ConnectionState.disconnected);
    _notifier.SetBtnConnectionActivity(BtnConnectionActivity.connect);
  }

  void subscribe()
  {
    client.subscribe(_topic, MqttQos.exactlyOnce);
  }

  void publish(String message) async
  {
    final MqttClientPayloadBuilder builder = MqttClientPayloadBuilder();
    builder.addString(message);
    client.publishMessage(_topic, MqttQos.exactlyOnce, builder.payload!);
  }
}
...
FilledButton(
                                onPressed: sendMessage,
                                child: Text("Send Text"))),
...
void sendMessage() {
    final text = controller.text;
    mqttManager.publish(text);
  }

When I call the connect() method inside the publish method with await and async, it works. But then is a second connection open.

Gropi
  • 1
  • If the connection to the broker goes down -- timeout? -- you will get this message. What is the unit of measure for the keepAlivePeriod? – JD Allen Mar 24 '23 at 20:03

1 Answers1

0

I think it better to check the connection every time before doing something, so its better to have a function isConnected :

bool isConnected() {
    return client.connectionStatus!.state == MqttConnectionState.connected;
  }

so when you want to pulish you need to check if you are connected first :

void publish(String message) async
  {
    if (isConnected()) {
      final MqttClientPayloadBuilder builder = MqttClientPayloadBuilder();
      builder.addString(message);
      client.publishMessage(_topic, MqttQos.exactlyOnce, builder.payload!);
    } else {
       debugPrint("You are not connect");
    }

  }

By the way, you dont need async in in the publish method, and also I recommend you to change type of connect from void to Future<void>, its doesn't change big thing but its still go to make the code more readable for other people :)