Home > other >  How to send ack to MQTT broker after receiving message
How to send ack to MQTT broker after receiving message

Time:09-23

I've created an app with NestJS to communicate with a broker an receive information from some publisher devices.

I need to send an ACK response to a specific topic to the broker after successfully receiving a message so the message is not send again.

When I create the microservice from the main file, I have no problem to listen and receive messages from the broker, but I don't find a way to send and publish a response.

For that reason I created a proxy client as the documentation shows but I cannot use the same client id because only one can be connected to the broker at the same time.

I can use a different client id, but in that case, the ack will not correspond to the client that received the message so it will be recived again.

I also tried to not configure the connection on the main file and just use the client inside the module, connect onApplicationBootstrap but the controller doesn't receive any message at all.

I suppose there must be another way of configuring the service so I can both listen and send at the same time, but I cannot figure out how to do it.

If anyone could help me on that or point on where to look to find a solution it will be much appreciated.

main.ts

import { NestFactory } from '@nestjs/core';
import { MqttOptions, Transport } from '@nestjs/microservices';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.createMicroservice<MqttOptions>(AppModule, {
    transport: Transport.MQTT,
    options: {
      url: 'mqtt://XX.XXX.XXX.XXXX:1883',
      clientId: 'my-client-id-test-001',
    },
  });
  await app.listen();
}
bootstrap();

app.module.ts

import { Module } from '@nestjs/common';
import {
  ClientsModule,
  OutgoingResponse,
  Transport,
} from '@nestjs/microservices';
import { AppController } from './app.controller';

@Module({
  imports: [
    ClientsModule.register([
      {
        name: 'MQTT_CLIENT',
        transport: Transport.MQTT,
        options: {
          url: 'mqtt://XX.XXX.XXX.XXX:1883',
          clientId: 'my-client-id-test-001',
          serializer: {
            serialize: (value: any): OutgoingResponse => value.data,
          },
          clean: false,
        },
      },
    ]),
  ],
  controllers: [AppController],
})
export class AppModule {}
import { Controller, Inject, OnApplicationBootstrap } from '@nestjs/common';
import {
  ClientProxy,
  Ctx,
  MessagePattern,
  MqttContext,
  Payload,
} from '@nestjs/microservices';

import { Message } from 'src/Message';

@Controller()
export class AppController implements OnApplicationBootstrap {
  constructor(@Inject('MQTT_CLIENT') private client: ClientProxy) {}

  async onApplicationBootstrap() {
    await this.client.connect();
  }

  @MessagePattern('GW/GPUB/682719248464')
  getPublishMessages(@Ctx() context: MqttContext, @Payload() payload: string) {
    console.log('recived data...');
    const message = new Message(payload);
    this.sendAck(
      'GW/SACK/682719248464',
      `ti=0F:${message.packetId}&id=${message.gatewayId}`,
    );
  }

  private sendAck(pattern: string, payload: string) {
    return this.client.send(pattern, payload);
  }
}

CodePudding user response:

MQTT messages do not contain any information about the publisher (e.g. clientid).

So if you send the response from another client (with a unique client id) the receiving subscriber will not be to determine the difference.

The only thing that could prevent this working is if the broker has an ACL that controls access to the topics based on clientid.

  • Related