Base

[中文]

  • Public header: #include "brookesia/service_helper/base.hpp"

Overview

esp_brookesia::service::helper::Base<Derived> is the CRTP base for Service Helpers, providing unified function calls, event subscriptions, and schema validation.

Features

  • CRTP contract: DerivedMeta requires FunctionId / EventId, get_name, get_*_schemas, etc.

  • Calls: call_function_sync / call_function_async with packing and parsing.

  • Events: Type-safe subscribe_event overloads.

  • Availability: is_available, get_function_schema, get_event_schema.

  • Timeouts: Optional Timeout(ms) on sync calls.

  • Macros: BROOKESIA_SERVICE_HELPER_FUNC_HANDLER_* for handler boilerplate.

Usage

Derive a helper with function/event enums and schemas:

class MyHelper : public esp_brookesia::service::helper::Base<MyHelper> {
public:
    enum class FunctionId { Ping };
    enum class EventId { Ready };
    static std::string_view get_name();
    static std::vector<FunctionSchema> get_function_schemas();
    static std::vector<EventSchema> get_event_schemas();
};

API Reference

Header File

Classes

template<typename Derived>
class Base

Base class for all service helpers (CRTP)

Note: Concept check is removed from template parameter to allow CRTP pattern where Derived is incomplete. Type and method checks are performed when methods are actually used via static_assert or compiler errors.

Template Parameters

Derived – The derived class (must be a subclass of Base)

Public Functions

template<typename EventIdType, typename Callable> inline  requires (has_event_name_first_param_v< Callable > &&!has_event_items_second_param_v< Callable >) static EventRegistry

Subscribe to an event with automatic parameter extraction.

// Event with two schema parameters: (string name, double value)
auto conn = subscribe_event(EventId::ValueChanged,
    [](const std::string &event_name, const std::string &name, double value) {
        std::cout << event_name << ": " << name << " = " << value << std::endl;
    });

// Event with no schema parameters, only event_name
auto conn = subscribe_event(EventId::Ready,
    [](const std::string &event_name) {
        std::cout << event_name << " triggered!" << std::endl;
    });

// Using string_view for event_name
auto conn = subscribe_event(EventId::StatusChanged,
    [](std::string_view event_name, bool status) {
        std::cout << event_name << ": " << (status ? "ON" : "OFF") << std::endl;
    });

Note

REQUIRED: First parameter must be std::string or std::string_view to receive event_name.

Note

Second parameter must not be EventItemMap; use the other overload for that case.

Note

Remaining parameters are extracted from EventItemMap based on the event-schema order.

Note

All non-event_name parameter types must satisfy the ConvertibleToEventItem concept.

Note

Parameter types must match the actual EventItem types in the map.

Template Parameters
  • EventIdType – Type of the event identifier (enum)

  • Callable – Type of the callable object (lambda, function, std::function, etc.) Event identifier is passed as event_id. Callable object is passed as callback, with first parameter as event_name and remaining parameters matching the event schema order.

Returns

EventRegistry::SignalConnection Connection object (scoped, automatically unsubscribes on destruction)

Public Static Functions

template<typename ReturnType>
static inline std::expected<ReturnType, std::string> process_function_result(const FunctionResult &result)

Helper function to process function result and convert to expected return type.

Parameters

result[in] Function result from service call

Returns

std::expected containing ReturnType or error message

template<typename ReturnType = void, typename FunctionIdType, typename ...Args>
static inline std::expected<ReturnType, std::string> call_function_sync(FunctionIdType function_id, Args&&... args)

Call a function synchronously with variadic arguments (timeout at end)

// No arguments with default timeout
auto result = call_function_sync<int>(FunctionId::GetValue);

// With arguments and default timeout
auto result = call_function_sync<int>(FunctionId::Add, 1.0, 2.0);

// With custom timeout at the end
auto result = call_function_sync<int>(FunctionId::Add, 1.0, 2.0, Timeout(500));

Note

Arguments are packed into std::vector<FunctionValue> in the order provided

Note

Last argument can be Timeout(milliseconds) to specify custom timeout

Note

All non-Timeout arguments must satisfy ConvertibleToFunctionValue concept

Template Parameters
  • ReturnType – Expected return type (default: void)

  • FunctionIdType – Type of the function identifier (enum)

  • Args – Types of function arguments (must be convertible to FunctionValue)

Parameters
  • function_id – Function identifier

  • args – Function arguments in order, last argument can be Timeout(ms)

Returns

std::expected<ReturnType, std::string> Function result or error

template<typename FunctionIdType, typename ...Args>
static inline bool call_function_async(FunctionIdType function_id, Args&&... args)

Call a function asynchronously with variadic arguments.

// No arguments
call_function_async(FunctionId::GetValue);

// With arguments
call_function_async(FunctionId::Add, 1.0, 2.0);

// With handler
call_function_async(FunctionId::Add, 1.0, 2.0, [](FunctionResult &&result) {
    // Handle result
});

Note

Arguments are packed into std::vector<FunctionValue> in the order provided

Note

All arguments (except optional FunctionResultHandler) must satisfy ConvertibleToFunctionValue concept

Note

This overload is not used when the first argument is FunctionParameterMap or boost::json::object

Template Parameters
  • FunctionIdType – Type of the function identifier (enum)

  • Args – Types of function arguments (must be convertible to FunctionValue, optionally with FunctionResultHandler at the end)

Parameters
  • function_id – Function identifier

  • args – Function arguments in order, optionally with FunctionResultHandler at the end

Returns

true if the call was successfully submitted, false otherwise

template<typename EventIdType>
static inline EventRegistry::SignalConnection subscribe_event(EventIdType event_id, EventRegistry::SignalSlot slot)

Subscribe to an event with a raw SignalSlot.

auto conn = subscribe_event(EventId::ValueChanged,
    [](const std::string &event_name, const EventItemMap &items) {
        // Handle event with raw items directly
    });

Template Parameters

EventIdType – Type of the event identifier (enum)

Parameters
  • event_id – Event identifier

  • slot – Signal slot function with signature: void(const std::string &event_name, const EventItemMap &event_items)

Returns

EventRegistry::SignalConnection Connection object (scoped, automatically unsubscribes on destruction)

template<typename T>
static inline FunctionResult to_function_result(std::expected<T, std::string> &&result)

Helper function to convert std::expected to FunctionResult.

Template Parameters

T – Return value type, can be void or any type convertible to FunctionValue

Parameters

result[in] std::expected object

Returns

FunctionResult Converted result

template<auto EventIdValue>
class EventMonitor

Event monitor for monitoring and waiting for specific events.

// Create a monitor for WiFi GeneralEventHappened
WifiHelper::EventMonitor<WifiHelper::EventId::GeneralEventHappened> monitor;
monitor.start();
// ... trigger some action ...
bool got_event = monitor.wait_for(std::vector<service::EventItem>{"Connected", false}, 5000);
monitor.stop();

Template Parameters

EventIdValue – The specific EventId enum value to monitor

Public Functions

inline bool start()

Start monitoring for events.

Returns

true if successfully started monitoring, false if already monitoring or failed

inline void stop()

Stop monitoring for events.

inline void clear()

Clear all received events.

inline bool wait_for(const ReceivedItmes &expected_items, uint32_t timeout_ms)

Wait for an event containing specific items.

Parameters
  • expected_items – The expected items to find

  • timeout_ms – Maximum time to wait in milliseconds

Returns

true if matching items were received, false on timeout

inline bool wait_for_any(uint32_t timeout_ms)

Wait for any event to be received within a timeout period.

Parameters

timeout_ms – Maximum time to wait in milliseconds

Returns

true if any event was received, false on timeout

inline size_t get_count() const

Get the number of received events.

Returns

Number of events received since start() or last clear()

inline bool has(const ReceivedItmes &expected_items) const

Check if specific items have been received.

Parameters

expected_items – The expected items to find

Returns

true if matching items exists in received items

inline const std::vector<ReceivedItmes> &get_all() const

Get all received events (unfiltered)

Returns

Copy of all received events

inline std::optional<ReceivedItmes> get_last() const

Get the last received event.

Returns

std::optional containing the last received items, std::nullopt if no items were received

template<typename ...Args>
inline std::vector<std::tuple<Args...>> get_all() const

Get received events filtered by item types and extracted as tuples.

// Get events where first item is string and second is bool
auto events = monitor.get_all<std::string, bool>();
for (const auto& [str_val, bool_val] : events) {
    // use str_val and bool_val
}

Template Parameters

Args – Expected types for each position in the event (bool, double, std::string, boost::json::object, boost::json::array, RawBuffer)

Returns

Vector of tuples containing extracted values from matching events

template<typename ...Args>
inline std::optional<std::tuple<Args...>> get_last() const

Get the last received event filtered by item types and extracted as tuple.

// Get last event where first item is string and second is bool
auto last_event = monitor.get_last<std::string, bool>();
if (last_event.has_value()) {
    const auto &[event_str, is_unexpected] = last_event.value();
    // Or use std::get<0>/std::get<1>
    const auto &event_str = std::get<0>(last_event.value());
    bool is_unexpected = std::get<1>(last_event.value());
}

// Get last event with single boost::json::array item
auto last_scan = monitor.get_last<boost::json::array>();
if (last_scan.has_value()) {
    const auto &ap_infos_array = std::get<0>(last_scan.value());
}

Template Parameters

Args – Expected types for each position in the event (bool, double, std::string, boost::json::object, boost::json::array, RawBuffer)

Returns

std::optional containing tuple of extracted values if the last event matches, std::nullopt if no events or type mismatch

inline bool is_running() const

Check if currently running.

Returns

true if actively running

Macros

BROOKESIA_SERVICE_HELPER_FUNC_HANDLER_0(Derived, function_id, func_call)

Create a zero-parameter function handler based on Derived and FunctionId.

Example: BROOKESIA_SERVICE_HELPER_FUNC_HANDLER_0(MyService, MyService::FunctionId::GetVolume, function_get_volume())

Parameters
  • Derived – The derived class type

  • function_id – FunctionId enum value

  • func_call – Actual function call (e.g., function_get_volume())

BROOKESIA_SERVICE_HELPER_FUNC_HANDLER_1(Derived, function_id, param_type, func_call)

Create a single-parameter function handler based on Derived and FunctionId.

Example: BROOKESIA_SERVICE_HELPER_FUNC_HANDLER_1(MyService, MyService::FunctionId::PlayUrl, std::string, function_play_url(PARAM))

Parameters
  • Derived – The derived class type

  • function_id – FunctionId enum value

  • param_type – Parameter C++ type (e.g., std::string, double)

  • func_call – Function call, use PARAM as parameter placeholder

BROOKESIA_SERVICE_HELPER_FUNC_HANDLER_2(Derived, function_id, param1_type, param2_type, func_call)

Create a two-parameter function handler based on Derived and FunctionId.

Example: BROOKESIA_SERVICE_HELPER_FUNC_HANDLER_2(MyService, MyService::FunctionId::Add, double, double, function_add(PARAM1, PARAM2))

Parameters
  • Derived – The derived class type

  • function_id – FunctionId enum value

  • param1_type – First parameter C++ type

  • param2_type – Second parameter C++ type

  • func_call – Function call, use PARAM1, PARAM2 as parameter placeholders

BROOKESIA_SERVICE_HELPER_FUNC_HANDLER_3(Derived, function_id, param1_type, param2_type, param3_type, func_call)

Create a three-parameter function handler based on Derived and FunctionId.

Example: BROOKESIA_SERVICE_HELPER_FUNC_HANDLER_3(MyService, MyService::FunctionId::SetConfig, std::string, int, bool, function_set_config(PARAM1, PARAM2, PARAM3))

Parameters
  • Derived – The derived class type

  • function_id – FunctionId enum value

  • param1_type – First parameter C++ type

  • param2_type – Second parameter C++ type

  • param3_type – Third parameter C++ type

  • func_call – Function call, use PARAM1, PARAM2, PARAM3 as parameter placeholders