{"id":20492066,"url":"https://github.com/zotonic/mqtt_packet_map","last_synced_at":"2025-09-09T14:46:30.400Z","repository":{"id":55476766,"uuid":"122966692","full_name":"zotonic/mqtt_packet_map","owner":"zotonic","description":"Encoder and decoder for MQTT v5 and earlier.","archived":false,"fork":false,"pushed_at":"2020-12-28T12:51:17.000Z","size":36,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-07-03T21:45:37.831Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zotonic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-26T12:27:24.000Z","updated_at":"2020-12-28T12:51:17.000Z","dependencies_parsed_at":"2022-08-15T01:10:52.360Z","dependency_job_id":null,"html_url":"https://github.com/zotonic/mqtt_packet_map","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/zotonic/mqtt_packet_map","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zotonic%2Fmqtt_packet_map","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zotonic%2Fmqtt_packet_map/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zotonic%2Fmqtt_packet_map/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zotonic%2Fmqtt_packet_map/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zotonic","download_url":"https://codeload.github.com/zotonic/mqtt_packet_map/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zotonic%2Fmqtt_packet_map/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274314618,"owners_count":25262694,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-09T02:00:10.223Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-15T17:27:31.743Z","updated_at":"2025-09-09T14:46:30.359Z","avatar_url":"https://github.com/zotonic.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/zotonic/mqtt_packet_map.svg?branch=master)](https://travis-ci.org/zotonic/mqtt_packet_map)\n\nMQTT Packet Encoder and Decoder\n===============================\n\nEncoder and decoder for MQTT v5 and earlier.\n\nMaps are used for the representation of all MQTT messages.\nThere are two functions:\n\n 1. `mqtt_packet_map:encode/1`\n 2. `mqtt_packet_map:decode/1`\n\nBoth have a variant where the MQTT version (protocol level) is passed.\nThis defaults to 5, valid values are 3, 4 (v3.1.1) and 5.\n\nExample usage:\n\n```erlang\n% Decode an incoming binary, return the message\ncase mqtt_packet_map:decode(Bin) of\n    {ok, {Msg, RestBin}} -\u003e\n        % Decoded a packet, RestBin contains the\n        % remaining data for the next packet(s).\n        ...;\n    {error, incomplete_packet} -\u003e ...;\n        % Packet is too short, fetch more data first\n        ...;\n    {error, malformed_header} -\u003e\n        % Illegal package, close the connection\n        ...;\n    {error, unknown_protocol} -\u003e\n        % Only for connect messages\n        ...\nend.\n\n% Encode a message\n{ok, Bin} = mqtt_packet_map:encode(Msg).\n\n% Encode a message as MQTT v3.1.1 (protocol level 4)\n{ok, Bin} = mqtt_packet_map:encode(4, Msg).\n```\n\nMQTT v5 Specification\n=====================\n\nThis library follows the following specification:\n\nhttp://docs.oasis-open.org/mqtt/mqtt/v5.0/cs01/mqtt-v5.0-cs01.html\n\n\nUsage\n=====\n\nInclude the mqtt_packet_map directly in your rebar.config:\n\n```erlang\n{deps, [\n    mqtt_packet_map\n]}.\n```\n\nTests\n=====\n\nRun tests with:\n\n```bash\nmake test\n```\n\nSample output:\n\n```\n./rebar3 ct --config rebar.test.config\n===\u003e Verifying dependencies...\n===\u003e Compiling mqtt_packet_map\n===\u003e Running Common Test suites...\n%%% mqtt_packet_map_SUITE ==\u003e variable_byte_integer: OK\n%%% mqtt_packet_map_SUITE ==\u003e partial_packet: OK\n%%% mqtt_packet_map_SUITE ==\u003e connect_v5: OK\n%%% mqtt_packet_map_SUITE ==\u003e connect_v5_full: OK\n%%% mqtt_packet_map_SUITE ==\u003e connack_v5: OK\n%%% mqtt_packet_map_SUITE ==\u003e publish_v5: OK\n%%% mqtt_packet_map_SUITE ==\u003e puback_et_al_v5: OK\n%%% mqtt_packet_map_SUITE ==\u003e subscribe_v5: OK\n%%% mqtt_packet_map_SUITE ==\u003e suback_v5: OK\n%%% mqtt_packet_map_SUITE ==\u003e unsubscribe_v5: OK\n%%% mqtt_packet_map_SUITE ==\u003e unsuback_v5: OK\n%%% mqtt_packet_map_SUITE ==\u003e pingreq: OK\n%%% mqtt_packet_map_SUITE ==\u003e pingresp: OK\n%%% mqtt_packet_map_SUITE ==\u003e disconnect_v5: OK\n%%% mqtt_packet_map_SUITE ==\u003e auth_v5: OK\nAll 15 tests passed.\n```\n\nPacket Types\n============\n\nBelow is the list of packet types and their fields.\n\nFields that are omitted are set to their defaults.\n\nFor example, `reason_code`, `qos`, and `packet_id` will\nall default to `0`.\n\nSome fields, like the topic for publish, are obligatory.\nThe encoder will crash if you leave out oblibatory fields.\n\nTopics\n------\n\nTopics are parsed as lists (i.e. they are split on the `/` separator).\n\nWhen encoding, both a binary and a list are accepted.\n\nSo the following are acceptable topics for the encoder:\n\n * `\u003c\u003c\"foo/bar\"\u003e\u003e`\n * `[ \u003c\u003c\"foo\"\u003e\u003e | \u003c\u003c\"bar\"\u003e\u003e ]`\n\nWhich are both decoded as:\n\n * `[ \u003c\u003c\"foo\"\u003e\u003e | \u003c\u003c\"bar\"\u003e\u003e ]`\n\n\nProperties\n----------\n\nThe (optional) properties of a package are represented as a map.\n\nKnown properties have an atom as key, user properties a binary.\n\nBelow is an example map with all properties and one user (`\u003c\u003c\"myuserprop\"\u003e\u003e`) property. The example values are random and\nhave no bearing in reality.\n\n```Erlang\n#{\n    payload_format_indicator =\u003e true,\n    message_expiry_interval =\u003e 1,\n    content_type =\u003e \u003c\u003c\"text/plain\"\u003e\u003e,\n    response_topic =\u003e [ \u003c\u003c\"response\"\u003e\u003e, \u003c\u003c\"topic\"\u003e\u003e ],\n    correlation_data =\u003e \u003c\u003c\"corrdata\"\u003e\u003e,\n    subscription_identifier =\u003e 2,\n    session_expiry_interval =\u003e 3,\n    assigned_client_identifier =\u003e \u003c\u003c\"assclientid\"\u003e\u003e,\n    server_keep_alive =\u003e 4,\n    authentication_method =\u003e \u003c\u003c\"authmethod\"\u003e\u003e,\n    authentication_data =\u003e \u003c\u003c\"authdata\"\u003e\u003e,\n    request_problem_information =\u003e true,\n    will_delay_interval =\u003e 5,\n    request_response_information =\u003e false,\n    response_information =\u003e \u003c\u003c\"respinfo\"\u003e\u003e,\n    server_reference =\u003e \u003c\u003c\"servref\"\u003e\u003e,\n    reason_string =\u003e \u003c\u003c\"reason\"\u003e\u003e,\n    receive_maximum =\u003e 12345,\n    topic_alias_maximum =\u003e 6,\n    topic_alias =\u003e 7,\n    maximum_qos =\u003e 2,\n    retain_available =\u003e true,\n    \u003c\u003c\"myuserprop\"\u003e\u003e =\u003e \u003c\u003c\"foobar\"\u003e\u003e,\n    maximum_packet_size =\u003e 1234567,\n    wildcard_subscription_available =\u003e true,\n    subscription_identifier_available =\u003e false,\n    shared_subscription_available =\u003e true\n}.\n```\n\nThe `subscription_identifier` can be present multiple times, making it either a single integer or a list of integers.\n\nCONNECT\n-------\n\nMinimal:\n\n```Erlang\n#{ type =\u003e connect }\n```\n\nComplete:\n\n```erlang\n #{\n    type =\u003e connect,\n    client_id =\u003e \u003c\u003c\"foobar\"\u003e\u003e,\n    username =\u003e \u003c\u003c\"someone\"\u003e\u003e,\n    password =\u003e \u003c\u003c\"secret\"\u003e\u003e,\n    clean_start =\u003e true,\n    keep_alive =\u003e 120,\n    properties =\u003e #{\n        \u003c\u003c\"foo\"\u003e\u003e =\u003e \u003c\u003c\"bar\"\u003e\u003e,\n        will_delay_interval =\u003e 10\n    },\n    will_flag =\u003e true,\n    will_payload =\u003e \u003c\u003c\u003e\u003e,\n    will_properties =\u003e #{},\n    will_qos =\u003e 0,\n    will_retain =\u003e false,\n    will_topic =\u003e [ \u003c\u003c\"good\"\u003e\u003e, \u003c\u003c\"bye\"\u003e\u003e ]\n}\n```\n\nCONNACK\n-------\n\nMinimal:\n\n```Erlang\n#{ type = connack }\n```\n\nComplete:\n\n```erlang\n#{\n    type =\u003e connack,\n    reason_code =\u003e 16#80,\n    session_present =\u003e true,\n    properties =\u003e #{\n        \u003c\u003c\"foo\"\u003e\u003e =\u003e \u003c\u003c\"bar\"\u003e\u003e\n    }\n}\n```\n\nPUBLISH\n-------\n\nMinimal:\n\n```Erlang\n#{\n    type =\u003e publish,\n    topic =\u003e [ \u003c\u003c\"foo\"\u003e\u003e, \u003c\u003c\"bar\"\u003e\u003e, \u003c\u003c\"la\"\u003e\u003e ]\n}\n```\n\nComplete:\n\n```erlang\n#{\n    type =\u003e publish,\n    topic =\u003e [ \u003c\u003c\"foo\"\u003e\u003e, \u003c\u003c\"bar\"\u003e\u003e, \u003c\u003c\"la\"\u003e\u003e ],\n    qos =\u003e 2,\n    dup =\u003e true,\n    retain =\u003e true,\n    packet_id =\u003e 1234,\n    payload =\u003e \u003c\u003c\"aloha\"\u003e\u003e,\n    properties =\u003e #{\n        \u003c\u003c\"foo\"\u003e\u003e =\u003e \u003c\u003c\"bar\"\u003e\u003e\n    }\n}\n```\n\nPUBACK / PUBREC / PUBREL / PUBCOMP\n----------------------------------\n\nThese for packets are the same. Only the type code is different.\n\nMinimal:\n\n```Erlang\n% Type is one of: puback, pubrec, pubrel, or pubcomp\n#{ type = puback }\n```\n\nComplete:\n\n```erlang\n#{\n    type =\u003e puback,\n    reason_code =\u003e 16#81,\n    packet_id =\u003e 4321,\n    properties =\u003e #{\n        \u003c\u003c\"bar\"\u003e\u003e =\u003e \u003c\u003c\"fooooo\"\u003e\u003e\n    }\n}\n```\n\n\nSUBSCRIBE\n-------\n\nThe topics subscribed to are either maps with options or just a topic.\n\nMinimal:\n\n```Erlang\n#{\n    type =\u003e subscribe,\n    topics =\u003e [\n        [ \u003c\u003c\"foo1\"\u003e\u003e, \u003c\u003c\"bar\"\u003e\u003e ]\n    ]\n}\n```\n\nComplete:\n\n```erlang\n#{\n    type =\u003e subscribe,\n    packet_id =\u003e 1234,\n    topics =\u003e [\n        #{\n            topic =\u003e [ \"foo1\", \"bar\" ],\n            no_local =\u003e true,\n            qos =\u003e 2,\n            retain_as_published =\u003e true,\n            retain_handling =\u003e 2\n        },\n        #{\n            topic =\u003e [ \u003c\u003c\"foo2\"\u003e\u003e, \u003c\u003c\"bar\"\u003e\u003e ]\n        }\n    ],\n    properties =\u003e #{\n        \u003c\u003c\"foo\"\u003e\u003e =\u003e \u003c\u003c\"bar\"\u003e\u003e\n    }\n}\n```\n\nSUBACK\n-------\n\nAll acknowledgements are tuples `{ok, QoS}` or `{error, ReasonCode}`.\n\nMinimal:\n\n```Erlang\n#{\n    type =\u003e suback,\n    acks =\u003e [\n        {ok, 0}\n    ]\n}\n```\n\nComplete (for four acks):\n\n```erlang\n#{\n    type =\u003e suback,\n    packet_id =\u003e 12345,\n    acks =\u003e [\n        {ok, 2},\n        {ok, 0},\n        {ok, 1},\n        {error, 16#80}\n    ],\n    properties =\u003e #{\n        \u003c\u003c\"foo\"\u003e\u003e =\u003e \u003c\u003c\"bar\"\u003e\u003e\n    }\n}\n```\n\nUNSUBSCRIBE\n-----------\n\nMinimal:\n\n```Erlang\n#{\n    type =\u003e unsubscribe,\n    topics =\u003e [\n        [ \u003c\u003c\"foo\"\u003e\u003e, \u003c\u003c\"bar\"\u003e\u003e ]\n    ]\n}\n```\n\nComplete:\n\n```erlang\n#{\n    type =\u003e unsubscribe,\n    packet_id =\u003e 42,\n    topics =\u003e [\n        \u003c\u003c\"foo1/bar\"\u003e\u003e,\n        [ \u003c\u003c\"foo2\"\u003e\u003e, \u003c\u003c\"bar\"\u003e\u003e ]\n    ],\n    properties =\u003e #{\n        \u003c\u003c\"foo\"\u003e\u003e =\u003e \u003c\u003c\"bar\"\u003e\u003e\n    }\n}\n```\n\nUNSUBACK\n-----------\n\nThe acknowledgements are one of:\n\n * `{ok, found}`\n * `{ok, notfound}`\n * `{error, ReasonCode}`\n\nMinimal:\n\n```Erlang\n#{\n    type =\u003e unsuback,\n    acks =\u003e [\n        {ok, found}\n    ]\n}\n```\n\nComplete (for three acks):\n\n```erlang\n#{\n    type =\u003e unsuback,\n    packet_id =\u003e 12345,\n    acks =\u003e [\n        {ok, found},\n        {ok, notfound},\n        {error, 16#80}\n    ],\n    properties =\u003e #{\n        \u003c\u003c\"foo\"\u003e\u003e =\u003e \u003c\u003c\"bar\"\u003e\u003e\n    }\n}\n```\n\nPINGREQ\n-------\n\nNo special fields.\n\n```Erlang\n#{ type =\u003e pingreq }\n```\n\nPINGRESP\n--------\n\nNo special fields\n\n```Erlang\n#{ type =\u003e pingresp }\n```\n\nDISCONNECT\n----------\n\nThe default reason code for disconnects is `0`.\n\nMinimal:\n\n```Erlang\n#{ type =\u003e disconnect }\n```\n\nComplete:\n\n```erlang\n#{\n    type =\u003e disconnect,\n    reason_code =\u003e 16#81,\n    properties =\u003e #{\n        \u003c\u003c\"foo\"\u003e\u003e =\u003e \u003c\u003c\"bar\"\u003e\u003e\n    }\n}\n```\n\nAUTH\n----\n\nMinimal:\n\n```Erlang\n#{ type =\u003e auth }\n```\n\nComplete:\n\n```erlang\n{\n    type =\u003e auth,\n    reason_code =\u003e 16#80,\n    properties =\u003e #{\n        \u003c\u003c\"foo\"\u003e\u003e =\u003e \u003c\u003c\"bar\"\u003e\u003e,\n        authentication_method =\u003e \u003c\u003c\"...\"\u003e\u003e,\n        authentication_data =\u003e \u003c\u003c\"...\"\u003e\u003e\n    }\n}\n```\n\n\nLicense\n=======\n\nThis library is licensed under the Apache License version 2.0.\n\nSee the LICENSE file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzotonic%2Fmqtt_packet_map","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzotonic%2Fmqtt_packet_map","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzotonic%2Fmqtt_packet_map/lists"}