| 
									
										
										
										
											2024-05-27 10:35:06 +02:00
										 |  |  | //
 | 
					
						
							|  |  |  | // Copyright (c) 2023-2024 Ivica Siladic, Bruno Iljazovic, Korina Simicevic
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Distributed under the Boost Software License, Version 1.0.
 | 
					
						
							|  |  |  | // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-17 09:46:07 +01:00
										 |  |  | //[publisher
 | 
					
						
							| 
									
										
										
										
											2024-10-08 09:59:35 +02:00
										 |  |  | #include <chrono>
 | 
					
						
							| 
									
										
										
										
											2024-03-15 09:40:39 +01:00
										 |  |  | #include <cstdlib>
 | 
					
						
							| 
									
										
										
										
											2023-11-17 09:46:07 +01:00
										 |  |  | #include <iostream>
 | 
					
						
							| 
									
										
										
										
											2024-10-08 09:59:35 +02:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2023-11-17 09:46:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-15 09:40:39 +01:00
										 |  |  | #include <boost/asio/as_tuple.hpp>
 | 
					
						
							| 
									
										
										
										
											2023-11-17 09:46:07 +01:00
										 |  |  | #include <boost/asio/co_spawn.hpp>
 | 
					
						
							|  |  |  | #include <boost/asio/detached.hpp>
 | 
					
						
							|  |  |  | #include <boost/asio/io_context.hpp>
 | 
					
						
							| 
									
										
										
										
											2024-03-15 09:40:39 +01:00
										 |  |  | #include <boost/asio/signal_set.hpp>
 | 
					
						
							|  |  |  | #include <boost/asio/steady_timer.hpp>
 | 
					
						
							| 
									
										
										
										
											2023-11-17 09:46:07 +01:00
										 |  |  | #include <boost/asio/use_awaitable.hpp>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <boost/asio/ip/tcp.hpp>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <async_mqtt5.hpp>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-07 09:32:34 +01:00
										 |  |  | #ifdef BOOST_ASIO_HAS_CO_AWAIT
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-15 09:40:39 +01:00
										 |  |  | // Modified completion token that will prevent co_await from throwing exceptions.
 | 
					
						
							|  |  |  | constexpr auto use_nothrow_awaitable = boost::asio::as_tuple(boost::asio::use_awaitable); | 
					
						
							| 
									
										
										
										
											2023-11-17 09:46:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-15 09:40:39 +01:00
										 |  |  | using client_type = async_mqtt5::mqtt_client<boost::asio::ip::tcp::socket>; | 
					
						
							| 
									
										
										
										
											2023-11-17 09:46:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-15 09:40:39 +01:00
										 |  |  | int next_sensor_reading() { | 
					
						
							|  |  |  | 	srand(static_cast<unsigned int>(std::time(0))); | 
					
						
							|  |  |  | 	return rand() % 100; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | boost::asio::awaitable<void> publish_sensor_readings( | 
					
						
							|  |  |  | 	client_type& client, boost::asio::steady_timer& timer | 
					
						
							|  |  |  | ) { | 
					
						
							| 
									
										
										
										
											2024-02-13 10:22:39 +01:00
										 |  |  | 	// Configure the Client.
 | 
					
						
							| 
									
										
										
										
											2024-01-16 13:04:21 +01:00
										 |  |  | 	// It is mandatory to call brokers() and async_run() to configure the Brokers to connect to and start the Client.
 | 
					
						
							| 
									
										
										
										
											2024-03-15 09:40:39 +01:00
										 |  |  | 	client.brokers("<your-mqtt-broker>", 1883) // Broker that we want to connect to. 1883 is the default TCP port.
 | 
					
						
							|  |  |  | 		.async_run(boost::asio::detached); // Start the client.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (;;) { | 
					
						
							|  |  |  | 		// Get the next sensor reading.
 | 
					
						
							|  |  |  | 		auto reading = std::to_string(next_sensor_reading()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Publish the sensor reading with QoS 1.
 | 
					
						
							|  |  |  | 		auto&& [ec, rc, props] = co_await client.async_publish<async_mqtt5::qos_e::at_least_once>( | 
					
						
							|  |  |  | 			"<your-mqtt-topic>", reading, | 
					
						
							|  |  |  | 			async_mqtt5::retain_e::no, async_mqtt5::publish_props {}, use_nothrow_awaitable | 
					
						
							|  |  |  | 		);		 | 
					
						
							|  |  |  | 		// An error can occur as a result of:
 | 
					
						
							|  |  |  | 		//  a) wrong publish parameters
 | 
					
						
							|  |  |  | 		//  b) mqtt_client::cancel is called while the Client is publishing the message
 | 
					
						
							|  |  |  | 		//     resulting in cancellation.
 | 
					
						
							|  |  |  | 		if (ec) { | 
					
						
							|  |  |  | 			std::cout << "Publish error occurred: " << ec.message() << std::endl; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Reason code is the reply from the server presenting the result of the publish operation.
 | 
					
						
							|  |  |  | 		std::cout << "Result of publish request: " << rc.message() << std::endl; | 
					
						
							|  |  |  | 		if (!rc) | 
					
						
							|  |  |  | 			std::cout << "Published sensor reading: " << reading << std::endl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Wait 5 seconds before publishing the next reading.
 | 
					
						
							|  |  |  | 		timer.expires_after(std::chrono::seconds(5)); | 
					
						
							|  |  |  | 		auto&& [tec] = co_await timer.async_wait(use_nothrow_awaitable); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// An error occurred if we cancelled the timer.
 | 
					
						
							|  |  |  | 		if (tec) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-11-17 09:46:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	co_return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int main() { | 
					
						
							|  |  |  | 	// Initialise execution context.
 | 
					
						
							| 
									
										
										
										
											2024-03-15 09:40:39 +01:00
										 |  |  | 	boost::asio::io_context ioc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialise the Client to connect to the Broker over TCP.
 | 
					
						
							|  |  |  | 	client_type client(ioc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialise the timer.
 | 
					
						
							|  |  |  | 	boost::asio::steady_timer timer(ioc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set up signals to stop the program on demand.
 | 
					
						
							|  |  |  | 	boost::asio::signal_set signals(ioc, SIGINT, SIGTERM); | 
					
						
							|  |  |  | 	signals.async_wait([&client, &timer](async_mqtt5::error_code /* ec */, int /* signal */) { | 
					
						
							|  |  |  | 		// After we are done with publishing all the messages, cancel the timer and the Client.
 | 
					
						
							|  |  |  | 		// Alternatively, use mqtt_client::async_disconnect.
 | 
					
						
							|  |  |  | 		timer.cancel(); | 
					
						
							|  |  |  | 		client.cancel(); | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2023-11-17 09:46:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Spawn the coroutine.
 | 
					
						
							| 
									
										
										
										
											2024-03-15 09:40:39 +01:00
										 |  |  | 	co_spawn(ioc.get_executor(), publish_sensor_readings(client, timer), boost::asio::detached); | 
					
						
							| 
									
										
										
										
											2023-11-17 09:46:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Start the execution.
 | 
					
						
							|  |  |  | 	ioc.run(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-07 09:32:34 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2024-02-13 10:22:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | //]
 |