#include "timer.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ranczo { class IHeater { public: virtual ~IHeater() = default; }; class HeaterBase : public IHeater { private: boost::asio::repeating_timer timer; protected: double _targetTemperature; double _histeresis; public: virtual void tick() { spdlog::info("ping"); }; HeaterBase(boost::asio::any_io_executor & io_executor) : timer{io_executor} { timer.start(boost::posix_time::seconds{1}, [&](const boost::system::error_code & e) { // TODO error handling spdlog::debug("Running timer"); this->tick(); }); } }; class IRelay { public: virtual ~IRelay() = default; virtual void setState(bool on) = 0; virtual void state() = 0; }; class ResistiveFloorHeater : public HeaterBase {}; class ModbusRelay : public IRelay {}; /// TODO /// * Przypisanie przełącznika do maty grzewczej /// * Zapis danych w DB /// * Zapis ustawień /// * Nasłuchiwanie na MQTT } // namespace ranczo // Modified completion token that will prevent co_await from throwing exceptions. using namespace std::chrono_literals; using boost::asio::yield_context; using timer = boost::asio::steady_timer; static auto now = timer::clock_type::now; // struct X : private boost::noncopyable { // int _id; // boost::asio::any_io_executor _executor; // std::string _topic; // X(boost::asio::any_io_executor io_executor, int id, std::string topic) : _executor{io_executor}, _c{_executor}, _id{id}, _topic{topic} { // spdlog::info("X for id/topic {}/{} created", _id, _topic); // spdlog::info("timer for id {} start", _id); // co_spawn(_executor, run_timer_id(), boost::asio::detached); // spdlog::info("mqtt for id/topic {}/{} start", _id, _topic); // co_spawn(_executor, subscribe_and_receive(_c, _topic), boost::asio::detached); // } // ~X() { // spdlog::info("X {} destroyed", _id); // } // boost::asio::awaitable< void > run_timer_id() { // auto executor = co_await boost::asio::this_coro::executor; // int counter{0}; // boost::asio::steady_timer timer{executor}; // while(true) { // timer.expires_after(std::chrono::seconds(1)); // co_await timer.async_wait(boost::asio::use_awaitable); // spdlog::info("Hello from {}:{}", counter++, _id); // } // co_return; // } // }; #include "mqtt_client.hpp" #include boost::asio::awaitable spawn(ranczo::AsyncMqttClient & c1){ spdlog::info("SPAWN subscribe"); co_await c1.subscribe("home/corridor/floor/temperature",[](const boost::json::value &){ spdlog::info("cb called"); }); spdlog::info("SPAWN listen"); co_await c1.listen(); spdlog::info("SPAWN return"); co_return; } int main() { spdlog::set_level(spdlog::level::trace); std::vector< std::unique_ptr< ranczo::IHeater > > _heaters; boost::asio::io_service io_service; /// Strand powoduje że zadania do niego przypisane zostają wykonane sekwencyjnie, /// get_executor pobrany z io_service nie daje takiej możliwości i wtedy można wykonywać zadania równloegle // boost::asio::any_io_executor io_executor = io_service.get_executor(); boost::asio::any_io_executor io_executor = boost::asio::make_strand(io_service); char buffer[2048]; std::pmr::monotonic_buffer_resource mbr(buffer, 2048, std::pmr::null_memory_resource()); // "home/corridor/floor/temperature" // "home/utilityRoom/floor/temperature" // "home/wardrobe/floor/temperature" // ranczo::AsyncMqttClient c1{io_executor}; // c1.add_subscribtion("home/corridor/floor/temperature", [](const boost::json::value &) { spdlog::info("cb called"); }); ranczo::PeriodicTimer timer{io_executor, std::chrono::seconds{1}, []() { spdlog::info("timer called"); }}; // xes.emplace_back(std::allocate_shared< X >(alloc, io_executor, 1, "home/corridor/floor/temperature")); // xes.emplace_back(std::allocate_shared< X >(alloc, io_executor, 2, "home/utilityRoom/floor/temperature")); // xes.emplace_back(std::allocate_shared< X >(alloc, io_executor, 3, "home/wardrobe/floor/temperature")); boost::asio::io_service::work work(io_service); io_service.run(); return 0; }