nestjsmqtt

How to send raw data as payload with MQTT on Nestjs


I want to send just raw data to the broker but the string is sent as string with quotations.

i.e. the message I want to sent is: ti=0F:0000000000&id=E8EB1BE99345 but what is sent is: "ti=0F:0000000000&id=E8EB1BE99345"

How can I achieve that?

I have declared serializer in the mqtt client like below,

@Module({
  imports: [
    ClientsModule.register([
      {
        name: 'MQTT_CLIENT',
        transport: Transport.MQTT,
        options: {
          url: 'mqtt://XX.XXX.XXX.XXX:1883',
          clientId: 'my-client-id',
          serializer: {
            serialize: (value: any) => value.data,
          },
        },
      },
    ]),
    ConfigModule.forRoot(),
  ],
  controllers: [AppController],
})
export class AppModule {}

You can see here that the ACKs are sent with the quotations, and they should be sent like above, without them:

enter image description here


Solution

  • Apparently this behaviour is something standard in Nestjs, the publishing response will be returned as the result object of applying JSON.stringify().

    There's no way of configure it anyhow.

    The only option for doing that is to create a custom ClientProxy or even easier extend from ClientMqtt and then override the publish method, so all the logic related with serialization is ignored, and just publish the raw data of the packet.

    Custom class with the modified publish method:

    import { ClientMqtt, ReadPacket, WritePacket } from '@nestjs/microservices';
    
    export class RawPayloadProxy extends ClientMqtt {
      protected publish(
        partialPacket: ReadPacket,
        callback: (packet: WritePacket) => any,
      ): () => void {
        try {
          const pattern = this.normalizePattern(partialPacket.pattern);
    
          const responseChannel = this.getResponsePattern(pattern);
          let subscriptionsCount =
            this.subscriptionsCount.get(responseChannel) || 0;
    
          const publishPacket = () => {
            subscriptionsCount = this.subscriptionsCount.get(responseChannel) || 0;
            this.subscriptionsCount.set(responseChannel, subscriptionsCount + 1);
            this.mqttClient.publish(
              this.getRequestPattern(pattern),
              partialPacket.data,
            );
          };
    
          if (subscriptionsCount <= 0) {
            this.mqttClient.subscribe(
              responseChannel,
              (err: any) => !err && publishPacket(),
            );
          } else {
            publishPacket();
          }
    
          return () => {
            this.unsubscribeFromChannel(responseChannel);
          };
        } catch (err) {
          callback({ err });
        }
      }
    }
    

    Definition of the custom client class on AppModule:

    @Module({
      imports: [
        ClientsModule.register([
          {
            name: 'MQTT_CLIENT',
            customClass: RawPayloadProxy,
            options: {
              url: 'mqtt://XX.XXX.XXX.XXX:1883',
              clientId: 'client-xxx',
            },
          },
        ]),
      ],
      controllers: [AppController],
    })
    export class AppModule {}