Net::M...:Simple(3pm)

okay bestie, gather round β€” this is Net::M...:Simple(3pm), straight outta the User Contributed Perl Documentation shelf. It's the manual page for the module Net::MQTT::Simple, and it is lowkey iconic for being tiny. Let's get into it. πŸŽ€


🌸 NAME 🌸

Net::MQTT::Simple β€” the absolute minimal MQTT version 3 interface. No cap. Just vibes and one file.


✨ SYNOPSIS ✨

# One-liner that publishes sensor values from STDIN

perl -MNet::MQTT::Simple=mosquitto.example.org \
     -nle'retain "topic/here" => $_'

# Functional (single server only)

use Net::MQTT::Simple "mosquitto.example.org";

publish "topic/here" => "Message here";
retain  "topic/here" => "Retained message here";

my $value = mqtt_get "topic/here";
my @values = mqtt_get [ "topic/one", "topic/two" ];

# Object oriented (supports subscribing to topics)

use Net::MQTT::Simple;

my $mqtt = Net::MQTT::Simple->new("mosquitto.example.org");

my $value = $mqtt->get("topic/here");
my @values = $mqtt->get([ "topic/one", "topic/two" ]);

$mqtt->publish("topic/here" => "Message here");
$mqtt->retain( "topic/here" => "Message here");

$mqtt->subscribe("topic/here" => sub {
    my ($topic, $message) = @_;
    ...
});

$mqtt->run(
    "sensors/+/temperature" => sub {
        my ($topic, $message) = @_;
        die "The building's on fire" if $message > 150;
    },
    "#" => sub {
        my ($topic, $message) = @_;
        print "[$topic] $message\n";
    },
);

πŸ’œ DESCRIPTION πŸ’œ

This module is literally one single file. It has no dependencies except the core Perl modules, which makes it the moment for embedded installs where you can't get a CPAN installer to work and resources are, like, scarce. Built different fr. πŸ¦‹

Only the basic MQTT functionality is here. If you need more than that, bestie, you're gonna have to go use the full-featured Net::MQTT instead. Sorry bout it. πŸ’…

Connections get set up on demand, and it'll automatically reconnect to the server if a previous connection got lost. Self-healing energy. ✨

And because sensor scripts are out here running unattended like little main characters, connection failures don't throw exceptions β€” they just throw warnings (on STDERR, unless you overrode that). Very chill of it.

Wanna know about encrypted and authenticated connections? Please refer to Net::MQTT::Simple::SSL for all of that. πŸ”

🌷 Functional interface

For most simple sensor scripts, this is honestly enough. A socket stays open and gets reused until the script finishes. The functional interface cannot be used for subscriptions β€” only for publishing. That's the ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ. 🚫

Instead of asking for symbols to be imported, you provide the MQTT server right there on the use Net::MQTT::Simple line. Got a non-standard port? Specify it after a colon. The functions publish, retain, and mqtt_get will get exported, and they call the methods publish, retain, and get respectively. Matchy matchy. πŸŽ€

πŸŽ€ Object oriented interface

new(server[, sockopts])

Hand the server to the constructor β€” Net::MQTT::Simple->new β€” possibly with a colon and a port number after it. The socket gets disconnected once the object goes out of scope. Bye girl πŸ‘‹

Optionally you can pass a reference to a hash of socket options. Anything you put in that hash gets passed on to the socket constructor. Customize away. πŸ’…

last_will([$topic, $message[, $retain]])

Set a "Last Will and Testament", which gets used on subsequent connections. Heads up though: the last will cannot be updated for a connection that's already established. Once it's set, it's set. πŸ™ˆ

So what even is a last will? It's a message that the broker publishes on behalf of the client if the connection gets dropped without an explicit call to disconnect. Dramatic exit, but make it protocol. πŸ’€

With no arguments at all, it returns the current values without changing the active configuration. Just peeking. πŸ‘€

When the given topic and message are both undef, the last will gets deconfigured. In every other case, only the arguments that are defined get updated with the given value. And for the very first setting: the topic is mandatory, the message defaults to an empty string, and the retain flag defaults to false.

Returns a list of the three values, in the same order as the arguments. 🌈

login($username[, $password])

Sets authentication credentials, used on subsequent connections. Same deal as the last will though β€” the credentials cannot be updated for a connection that's already established. 🚫

The username is text. The password is binary. Know the difference, bestie, it matters.

For info about secure connections, see Net::MQTT::Simple::SSL. And if you wanna enable insecure password authenticated connections, set the environment variable MQTT_SIMPLE_ALLOW_INSECURE_LOGIN to a true value. Do it at your own risk, no judgment. πŸ™ˆ

Returns the username.


πŸ•ŠοΈ DISCONNECTING GRACEFULLY πŸ•ŠοΈ

disconnect

Performs a graceful disconnect, which ensures that the server does NOT send the registered "Last Will" message. So you leave quietly instead of making a scene. Iconic behavior. ✨

Any subsequent calls that need a connection will cause a brand new connection to be set up. Rebirth era. πŸ¦‹


πŸ“¨ PUBLISHING MESSAGES πŸ“¨

The two methods for publishing messages are exactly the same, except for the state of the retain flag. That's the whole difference. 🀝

retain(topic, message)

Publishes the message with the retain flag on. Use this for sensor values, or anything else where the message is telling you the current status of something. It's the "this is how things are right now" vibe. πŸ“Œ

Wanna discard a retained topic? Provide an empty or undefined message. Poof, gone. πŸ’¨

publish(topic, message)

Publishes the message with the retain flag off. Use this for ephemeral messages about things that happen β€” like somebody pressed a button. Blink and it's over. ⚑


πŸ‘‚ SUBSCRIPTIONS πŸ‘‚

Small but crucial: any one topic should be used with subscribe, once, or get β€” but not multiple methods simultaneously. Pick a lane, bestie. πŸ›‘

subscribe(topic, handler[, topic, handler, ...])

Subscribes to the given topic(s) and registers the callbacks. Important note: only the first matching handler will be called for every message, even if the filter patterns overlap. First come, first served. πŸ’…

unsubscribe(topic[, topic, ...])

Unsubscribes from the given topic(s) and unregisters the corresponding callbacks. The topics you pass here must exactly match topics that were previously used with the subscribe method. Exact string match, no approximate vibes. 🎯

once(topic, handler)

Subscribes to a topic, and then unsubscribes from that topic after the first message matching the topic has been received and the handler has been called. One and done. ✨

get(topics[, timeout])

Returns the first message received for one or more topics. This one is specifically useful when combined with retained messages. Chef's kiss. πŸ‘‘

  • Given a single topic (a string)? You get back the single message.
  • Given multiple topics (a reference to an array of strings)? You get back a reference to an array of messages in scalar context, or the messages themselves in list context.

The timeout is expressed in whole seconds and defaults to 1. Fair warning: the actual time waited may be up to 1 second longer than what you specified. It's not late, it's fashionably delayed. πŸ’…

run(...)

Enters an infinite loop, which calls tick over and over. If you give it any arguments, they get passed to subscribe first. Set it and forget it. πŸ”

tick(timeout)

Tests the socket to see if there's any incoming message, waiting at most timeout seconds (and yes, that can be fractional). Use a timeout of 0 to avoid blocking β€” but heads up, blocking automatic reconnection may take place anyway, and that can take much longer. πŸ™ˆ

If tick returns false, that means the socket was no longer connected, and the next call will cause a reconnection attempt. However!! A true value does not necessarily mean the socket is still functional. 😭

The only way to reliably determine that a TCP stream is still connected is to actually communicate with the server β€” like with a ping β€” which is only done periodically. Them's the facts.


πŸ› οΈ UTILITY FUNCTIONS πŸ› οΈ

Net::MQTT::Simple::filter_as_regex(topic_filter)

Give it a valid MQTT topic filter, and it hands you back the corresponding regular expression. Little translator moment. 🧚


🌐 IPv6 PREREQUISITE 🌐

For IPv6 support, the module IO::Socket::IP needs to be installed. The good news? It comes with Perl 5.20, and it's available from CPAN for older Perls. πŸŽ‰

If that module isn't available, the older IO::Socket::INET gets used instead β€” and that one only supports Legacy IP (IPv4). Sad but true. πŸ˜”


πŸ“¦ MANUAL INSTALLATION πŸ“¦

If you can't use the CPAN installer, you can actually install this module by hand: create a directory Net/MQTT and drop Simple.pm in it. That's it. 🫢

But please note: this method does not work for every Perl module, and it should be used only as a last resort on systems where proper installers aren't available. It's the emergency backup plan, not the main plan. 🚨

Wanna see the list of @INC paths where Perl goes looking for modules? Run perl -V. That list includes the current working directory (.) β€” sneaky. You can also specify additional include paths in the PERL5LIB environment variable; see perlenv for the details. πŸŽ€


❌ NOT SUPPORTED ❌

QoS (Quality of Service)

Every message is published at QoS level 0, which is "at most once" β€” also known as "fire and forget". You send it, you hope for the best, you move on. πŸ’…

DUP (Duplicate message)

Since QoS isn't supported, no retransmissions are done, and no message will indicate that it's already been sent before. Nothing gets a do-over. 🚫

Large data

Everything is handled in memory, and there's no way to tell the server that large messages aren't wanted β€” so the connection gets dropped as soon as the server announces a packet larger than 2 megabytes. So if you're, like, trying to send your entire camera roll, no. πŸ’€

Validation of server-to-client communication

The MQTT spec prescribes mandatory validation of all incoming data, and disconnecting if anything β€” really, anything β€” is wrong with it. But this minimal implementation just silently ignores anything it doesn't specifically handle, which can lead to weird behaviour if the server sends out bad data. πŸ™ˆ

Fun fact though: most clients don't adhere to this part of the specifications either. So we're in good (bad?) company.


🚧 CAVEATS 🚧

πŸ” Automatic reconnection

Connection and reconnection are handled automatically β€” but without retries. If anything goes wrong, that causes a single reconnection attempt before the following action.

For example: if sending a message fails because the socket got disconnected, the message will not be resent β€” but the next message might succeed. Only one new connection attempt is done per approximately 5 seconds. This behaviour is intended. Yes, on purpose. It's giving "I'll get to it when I get to it." 😌

πŸ”€ Unicode

This module uses the proper Perl Unicode abstractions for the parts that, according to the MQTT specification, are UTF-8 encoded. That includes topics β€” but not messages. Published messages are binary data, and you may have to encode and decode them yourself. You got this. πŸ’ͺ

This means: if you've got UTF-8 encoded string literals in your code, you should use utf8; β€” and any of those strings which is a message will need to be encoded by you, for example with utf8::encode($message);. 🧚

It also means a message should never contain any character with an ordinal value greater than 255, because those cannot be used in binary communication. If you're passing non-ASCII text strings: encode them before publishing, decode them after receiving. πŸ“¨

A character greater than 255 results in a warning:

Wide character in publish at yourfile.pl line 42.

...while the UTF-8 encoded data is passed through anyway. To get rid of that warning, use utf8::encode($message);. Problem solved, bestie. ✨

πŸ’– LICENSE πŸ’–

okay so legally speaking, bestie, this software can be redistributed under the terms of the GPL, the LGPL, the modified BSD license, or the Artistic license β€” or any of the other OSI approved licenses listed over at http://www.opensource.org/licenses/alphabetical. like, distribution is allowed under all of these licenses, or any smaller subset of multiple of them, or honestly just one of them. pick your fighter, she ate πŸ’…

When you're using a packaged version, bestie, please refer to the package metadata to see under which license terms it was distributed, okurrr? Alternatively β€” and this is the slay part β€” a distributor may choose to replace the LICENSE section of the documentation and/or include a LICENSE file to reflect the license(s) they chose to redistribute under. so it's giving "choose your own adventure" but for legalese πŸŽ€


πŸ‘‘ AUTHOR πŸ‘‘

Juerd Waalboer <juerd@tnx.nl> β€” the main character who wrote all this. we stan. 🫢


🌈 SEE ALSO 🌈

  • Net::MQTT
  • Net::MQTT::Simple::SSL

go read those too, iykyk πŸ’œ


k that's literally the whole page, bestie!! this was part of the Net::MQTT::Simple(3pm) docs, shipped as perl v5.40.1 and dated 2025-12-22. no cap, you made it to the end, so treat yourself to a lil snack, you legend πŸ“βœ¨πŸ’– bye bestie!! πŸ¦‹πŸŒΈπŸ’…

πŸ“¦ where this page comes from