Codec & Payloads

View Source

Packet Codec

The packet codec supports all 15 MQTT packet types across MQTT 3.1, 3.1.1, and 5.0:

# Encode a PUBLISH packet (MQTT 3.1.1 = version 4)
packet = %{type: :publish, topic: "test/topic", payload: "hello", qos: 0, retain: false}
{:ok, binary} = MqttX.Packet.Codec.encode(4, packet)

# Decode
{:ok, {decoded, rest}} = MqttX.Packet.Codec.decode(4, binary)

# Encode to iodata (more efficient for socket writes)
{:ok, iodata} = MqttX.Packet.Codec.encode_iodata(4, packet)

Protocol Versions

VersionProtocol
3MQTT 3.1
4MQTT 3.1.1
5MQTT 5.0

Supported Packet Types

CONNECT, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, PINGREQ, PINGRESP, DISCONNECT, AUTH (MQTT 5.0 only).

Performance

The codec is optimized with zero-copy binary references, unrolled varint decoding, and iodata output to avoid concatenation.

Benchmarks vs mqtt_packet_map (Apple M4 Pro):

OperationMqttXmqtt_packet_mapSpeedup
PUBLISH encode5.05M ips1.72M ips2.9x
SUBSCRIBE encode3.42M ips0.82M ips4.2x
PUBLISH decode2.36M ips2.25M ips~1x

Payload Codecs

MqttX includes pluggable payload codecs for encoding/decoding message payloads. All codecs implement the MqttX.Payload behaviour.

JSON (OTP 27+ / Elixir 1.18+)

Uses the built-in Erlang JSON module - no external dependencies:

{:ok, json} = MqttX.Payload.JSON.encode(%{temp: 25.5, humidity: 60})
{:ok, data} = MqttX.Payload.JSON.decode(json)

Protobuf

Requires the {:protox, "~> 2.0"} optional dependency:

{:ok, binary} = MqttX.Payload.Protobuf.encode(my_proto_struct)
{:ok, struct} = MqttX.Payload.Protobuf.decode(binary, MyProto.Message)

Raw (Pass-through)

No transformation - binary in, binary out:

{:ok, binary} = MqttX.Payload.Raw.encode(<<1, 2, 3>>)
{:ok, binary} = MqttX.Payload.Raw.decode(<<1, 2, 3>>)

Custom Codecs

Implement MqttX.Payload for your own formats:

defmodule MyApp.MsgPackCodec do
  @behaviour MqttX.Payload

  @impl true
  def encode(term), do: {:ok, Msgpax.pack!(term)}

  @impl true
  def decode(binary), do: {:ok, Msgpax.unpack!(binary)}
end