From 5f2528eddbe14a62fb95fc873777954d98938ffe Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Wed, 8 Jul 2026 19:30:28 +0500 Subject: [PATCH 1/2] make use new connectivity policy --- main/controller.cpp | 178 ++++++++++++++++++++++++++++---------------- 1 file changed, 115 insertions(+), 63 deletions(-) diff --git a/main/controller.cpp b/main/controller.cpp index 9e753b5..9fc279c 100644 --- a/main/controller.cpp +++ b/main/controller.cpp @@ -22,6 +22,8 @@ #include "sensors/sensors.h" #include "sleeping/sleeping.h" +using namespace std::chrono_literals; + /** * Standard uid for test application. * This is intended to use only for testing purposes due to its limitations. @@ -51,21 +53,46 @@ static const auto kWifiInit = ae::WiFiInit{ }; #endif +struct WorkMode { + using type = std::uint8_t; + static constexpr type kTx = 0x1, kRx = 0x2, kTxRx = 0x3; + + static std::string_view ToText(type v) { + switch (v) { + case WorkMode::kTx: + return "TX"; + case WorkMode::kRx: + return "RX"; + case WorkMode::kTxRx: + return "TX+RX"; + default: + return "NONE"; + } + } +}; + +static constexpr ae::Duration kTxInterval = 30s; +static RTC_STORAGE_ATTR ae::TimePoint next_tx_time = {}; + +// Client selection handler +void ClientSelected(ae::Result res); // Update temperature sensor void UpdateSensors(); // Message from aether service received void MessageReceived(ae::DataBuffer const& buffer); // Send the message value to the aether service void SendValue(std::int16_t temperature); +// Make all required work and ready to sleep +void SleepReady(); // Go to sleep method -void GoToSleep(ae::Uap::Timer uap_timer); +void GoToSleep(ae::TimePoint time_point); static ae::RcPtr aether_app; +static ae::Client::ptr client; static std::unique_ptr message_stream; void setup() { - std::cout << ae::Format("Setup {:%Y-%m-%d %H:%M:%S}") << ae::Now() - << std::endl; + std::cout << ae::Format("Setup {:%Y-%m-%d %H:%M:%S}\n") << ae::Now(); aether_app = ae::AetherApp::Construct( ae::AetherAppContext{} @@ -81,60 +108,14 @@ void setup() { kWifiInit); }) # endif - .UapFactory([](ae::AetherAppContext const& context) { - auto uap = context.aether()->uap; - if (uap.is_valid()) { - return uap; - } - // configure uap - // 60secs for send/receive - // then 2 times by 30 seconds for send only - return ae::Uap::ptr::Create( - ae::CreateWith{context.domain()}.with_id(ae::GlobalId::kUap), - context.aether(), - std::initializer_list{ - ae::Interval{.type = ae::IntervalType::kSendReceive, - .duration = std::chrono::seconds{60}, - .window = std::chrono::seconds{10}}, - ae::Interval{.type = ae::IntervalType::kSendOnly, - .duration = std::chrono::seconds{30}}, - ae::Interval{.type = ae::IntervalType::kSendOnly, - .duration = std::chrono::seconds{30}}}); - }) #endif ); - // setup sleep on uap event - aether_app->aether()->uap->sleep_event().Subscribe(GoToSleep); - // select controller's client - auto& select_client = - aether_app->aether()->SelectClient(kParentUid, "Controller"); - - select_client.result_event().Subscribe( - [&](ae::Result&& res) { - if (res) { - ae::Client::ptr client = std::move(res).value(); - client.WithLoaded([](auto const& c) { - std::cout << Format( - "\n\n>>>>>>>\n>>>>>>> Client Loaded UID:{} \n>>>>>>> Visit " - "https://aethernet.io/smarthub.html?uuid={} \n<<<<<\n\n", - c->uid(), kServiceUid); - - // open message stream to aether service client - message_stream = std::make_unique( - *aether_app, c, kServiceUid, - c->message_stream_manager().CreatePort(kServiceUid)); - message_stream->out_data_event().Subscribe(MessageReceived); - - // measure temperature and send updated value - UpdateSensors(); - }); - } else { - std::cerr << " !!! Client selection error"; - aether_app->Exit(1); - } - }); + aether_app->aether() + ->SelectClient(kParentUid, "Controller") + .result_event() + .Subscribe(&ClientSelected); } void loop() { @@ -152,6 +133,60 @@ void loop() { } } +void ClientSelected(ae::Result res) { + if (!res) { + std::cerr << " !!! Client selection error\n"; + aether_app->Exit(1); + return; + } + + client = std::move(res).value(); + auto r = client.WithLoaded([](ae::Ptr const& c) { + std::cout << ae::Format( + "\n\n>>>>>>>\n>>>>>>> Client Loaded UID:{} \n>>>>>>> Visit " + "https://aethernet.io/smarthub.html?uuid={} \n<<<<<\n\n", + c->uid(), kServiceUid); + + // Config connectivity policy, open 5s RX window every 60s. + c->connectivity_policy() + ->ConfigureRxTimings(ae::RequestPolicy::All{}) + .ForAllPriorities(ae::RxTimingConf::Every(60s).WithWindow(5s)); + + // check current work_mode + // it's always TX if we woke up + auto work_mode = WorkMode::kTx; + auto current_time = ae::Now(); + static constexpr ae::Duration threshold = 5s; + auto cp_status = c->connectivity_policy()->GetStatus(); + // if it's next_service_time it's also RX + if ((current_time + threshold) >= cp_status.next_service_time) { + work_mode = work_mode | WorkMode::kRx; + } + std::cout << ae::Format(">>>> Run in {} work mode\n", + WorkMode::ToText(work_mode)); + + if ((work_mode & WorkMode::kRx) != 0) { + // open message stream for receive and send + message_stream = std::make_unique( + *aether_app, c, kServiceUid, + c->message_stream_manager().CreatePort(kServiceUid)); + message_stream->out_data_event().Subscribe(MessageReceived); + } else { + // open message stream for send only + message_stream = std::make_unique( + *aether_app, c, kServiceUid, ae::P2pPortHandle{}); + } + + // measure temperature and send updated value + UpdateSensors(); + }); + + if (!r) { + std::cerr << " !!! Client wasn't loaded"; + aether_app->Exit(2); + } +} + // implemented in sensors/ void UpdateSensors() { std::int16_t temperature = {}; @@ -195,28 +230,45 @@ void SendValue(std::int16_t temperature) { message_stream->Write(std::move(message)).status_event().Subscribe([](auto) { // with any result ready to sleep - aether_app->aether()->uap->SleepReady(); + SleepReady(); }); + + next_tx_time = ae::Now() + kTxInterval; +} + +void SleepReady() { + auto go_to_sleep = [](auto next_rx_time) noexcept { + auto next_time = std::min(next_tx_time, next_rx_time); + std::cout << ae::Format( + ">> Go to sleep no wait, next_tx_time {}, next_rx_time {}\n", + next_tx_time, next_rx_time); + GoToSleep(next_time); + }; + + auto status = client->connectivity_policy()->GetStatus(); + if (status.can_suspend) { + go_to_sleep(status.next_service_time); + } else { + std::cout << ">>> Wait for can suspend\n"; + client->connectivity_policy()->suspend_allowed_event().Subscribe([&]() { + go_to_sleep(client->connectivity_policy()->GetStatus().next_service_time); + }); + } } -void GoToSleep(ae::Uap::Timer uap_timer) { +void GoToSleep(ae::TimePoint time_point) { std::cout << " >>> Going to sleep...\n"; if (!aether_app) { return; } - - // get the interval with the specified offset - // offset is required to account the Save operation - auto interval = uap_timer.interval(std::chrono::seconds{10}); // save current aether state aether_app->aether().Save(); + // Go to sleep - auto sleep_until = interval.until(); std::cout << ae::Format( " >>> Sleep from {:%Y-%m-%d %H:%M:%S} until {:%Y-%m-%d %H:%M:%S}...\n", - ae::Now(), sleep_until); + ae::Now(), time_point); // TODO: add separate sleep duration - DeepSleep(interval.until(), interval.until(), - 3000); // wait till time or 30 deegrees + DeepSleep(time_point, time_point, 3000); // wait till time or 30 deegrees } From 55d4aeba47bc47f0a2d04d6eee97a268c87a3b62 Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Wed, 15 Jul 2026 14:47:49 +0500 Subject: [PATCH 2/2] add missing include iostream --- main/controller.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/main/controller.cpp b/main/controller.cpp index 9fc279c..0e8eb2a 100644 --- a/main/controller.cpp +++ b/main/controller.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "aether/all.h" #include "sensors/sensors.h"