Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide an example of how to receive only one retained message #17

Open
dmak opened this issue Feb 17, 2022 · 4 comments
Open

Provide an example of how to receive only one retained message #17

dmak opened this issue Feb 17, 2022 · 4 comments

Comments

@dmak
Copy link

dmak commented Feb 17, 2022

I wonder how to implement the following functionality:

mosquitto_sub -C 1 -t ...

i.e. read one (retained) message from the topic.

The following code does not wait for 5 seconds and also does not receive any message from the topic (prints Tick: 1 to the console):

my $mqtt = Net::MQTT::Simple->new(MQTT_HOST);
$mqtt->login($mqtt_user, $mqtt_pass);
$mqtt->subscribe(MQTT_TOPIC, sub {
	shift;
	print "Received the message: " . shift . "\n";
});
print "Tick: " . $mqtt->tick(5) . "\n";
$mqtt->disconnect();

Thanks in advance!

@Juerd
Copy link
Owner

Juerd commented Feb 17, 2022 via email

@dmak
Copy link
Author

dmak commented Feb 18, 2022

Thanks. The utility calls run() function (which I cannot afford as it enters the endless loop) and calls exit() to abort the program from message handler.
I need exactly the logic I've described: receive the message from the topic and then the program flow continues. If there is no message send by the server, then wait some time and continue:

my $message = undef;
$mqtt->subscribe(MQTT_TOPIC, sub {
	shift;
	$message = shift;
});
# ... some long-running initialization ...
if (!$message) {
	$mqtt->tick(5); # give one more chance to receive the message
	if (!$message) {
		$mqtt->unsubscribe(MQTT_TOPIC);
		$message = { 'default' => 'value' };
	}
}
# ... the program continues either with received message or with default values ...

The only way I see this can be implemented with utility approach is when:

  • The function run() is added a timeout argument which specifies now many seconds the loop may cycle.
  • The message handler may return a special return code to signal that loop should exit.

Then it can be implemented the suggested way:

$mqtt->subscribe(MQTT_TOPIC, sub {
	$message = $_[1];
	return BREAK_LOOP;
});
$mqtt->run(5);

@christianTF
Copy link

@dmak
Copy link
Author

dmak commented Feb 18, 2022

Thanks for the example, that is actually what I was thinking about: call subscribe() then sleep() + tick() (however that is not efficient). But if this is a "standard" usecase, why it cannot library help here?

Currently tick() returns also when PINGRESP (type 13) is received while generally one would be interested only in messages for subscribed topics. The meta-code for the better helper is:

my $time_ms = time_ms();
while ($timeout_ms > 0) {
  if (select($timeout_ms / 1000)) {
    sysread();
    _parse();
    my $message_dispatched_to_topic = _dispatch_message();
    if ($message_dispatched_to_topic) {
      last;
    }
    // message is a service message
    my $current_time_ms = time_ms();
    $timeout_ms -= ($current_time_ms - $time_ms);
    $time_ms = $current_time_ms;
  } else {
    // no event for the given timeout
    last;
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants