Stefan de Kraker
Stefan de Kraker

Reputation: 363

Flutter Mqtt callback with BLoC

I'm building a Flutter Embedded application that uses MQTT to communicate between processes. Currently, I have a repository that subscribes to specific MQTT topics, but I want to improve it by triggering BLoC events when messages are received.

Current Approach: I’ve created a stream for each topic and have a method that listens to these streams, processes the data, and handles the topic. However, I don’t know the type of data in advance, and the logic feels a bit scattered. Here's what my current code looks like:

void _routeMessages() {
  client.updates!.listen((List<MqttReceivedMessage<MqttMessage>>? c) {
    for (var message in c!) {
      var payload = message.payload as MqttPublishMessage;
      var data = MqttPublishPayload.bytesToStringAsString(payload.payload.message);
      var topic = message.topic;
      log('Data received on: $topic', name: 'mqttService | _routeMessages');
      // HERE I WOULD LIKE TO TRIGGER A BLoC EVENT
      // Call the appropriate BLoC event based on the topic, e.g., OnSku event
    }
  });
}

class A extends Bloc<Aevent, AState> {
    on<OnSKU>((event, emit) {
      // HERE PROCESS THE MQTT DATA
    });

    add(Subscribe({OnSKU: 'machine/backup/sku'}));
}

Goal: Instead of manually handling each topic and parsing the data, I would like to subscribe to a topic, provide a BLoC event for it, and automatically dispatch that event when a message is received for that topic. This way, the corresponding BLoC will handle the event, process the data, and update the state accordingly.

 Future<void> _subscribeAndEmit(Subscribe event, Emitter<MachineDataState> emit) async {
  if (_repository.isConnected()) {
    // Subscribe to the topic and set its parser
    _repository.subscribe(event.handler);
    // Listen to the topic stream and emit states
    await emit.forEach(
      _repository.getStreamForTopic(event.handler),
      onData: (parsedData) {
        final topic = event.handler.topic;
        final String? data = parsedData == 'null' ? null : parsedData;
        if (topic == MqttTopics.get('backup', 'sku')) {
          recievedData['sku'] = data;
          emit(MachineDataReceived(data: recievedData));
        }
        if (topic == MqttTopics.get('backup', 'serial')) {
          recievedData['serial'] = data;
          emit(MachineDataReceived(data: recievedData));
        }
        if (topic == MqttTopics.get('backup', 'model')) {
          recievedData['model'] = data;
          emit(MachineDataReceived(data: recievedData));
        }
        if (topic == MqttTopics.get('backup', 'lifetime')) {
          recievedData['lifetime'] = data;
          emit(MachineDataReceived(data: recievedData));
        }
        return Initial();
      },
      onError: (error, stackTrace) {
        return Error(error: error.toString());
      },
    );
  } else {
    emit(Error(error: Strings.errorNotConnected));
  }
}

However, I would like to simplify this process and allow the repository to directly trigger a BLoC event when a message is received, instead of manually checking each topic and dispatching the event.

My Question: Is it possible to refactor the repository so that it triggers the appropriate BLoC event automatically when a message is received for a given topic? I’m looking for a cleaner and more elegant way to achieve this.

If this approach isn’t feasible, are there alternative solutions to achieve a similar result?

Upvotes: 0

Views: 20

Answers (0)

Related Questions