基类

[English]

  • 公共头文件: #include "brookesia/service_helper/base.hpp"

概述

esp_brookesia::service::helper::Base<Derived> 是 Service Helper 体系的 CRTP 基类,为各具体 helper 提供统一的函数调用、事件订阅与 schema 校验能力。

特性

  • CRTP 契约约束:通过 DerivedMeta 要求派生类提供 FunctionId/EventId/get_name/get_*_schemas 等标准元信息。

  • 统一函数调用:提供 call_function_synccall_function_async,自动完成参数打包与返回值解析。

  • 类型安全事件订阅:提供多种 subscribe_event 重载,支持按回调签名自动适配事件参数。

  • 服务可用性检查:通过 is_availableget_function_schemaget_event_schema 快速判断和获取能力描述。

  • 超时控制:同步调用支持在参数末尾附加 Timeout(ms),用于控制等待时长。

  • 回调适配宏:提供 BROOKESIA_SERVICE_HELPER_FUNC_HANDLER_*,简化服务函数注册时的参数转换样板代码。

使用方式

派生 helper 需定义函数/事件枚举和 schema,并继承 Base<Derived> 复用通用调用逻辑。

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 参考

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.

模板参数

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;
    });

备注

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

备注

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

备注

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

备注

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

备注

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

模板参数
  • 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.

返回

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.

参数

result[in] Function result from service call

返回

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));

备注

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

备注

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

备注

All non-Timeout arguments must satisfy ConvertibleToFunctionValue concept

模板参数
  • ReturnType – Expected return type (default: void)

  • FunctionIdType – Type of the function identifier (enum)

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

参数
  • function_id – Function identifier

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

返回

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
});

备注

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

备注

All arguments (except optional FunctionResultHandler) must satisfy ConvertibleToFunctionValue concept

备注

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

模板参数
  • FunctionIdType – Type of the function identifier (enum)

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

参数
  • function_id – Function identifier

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

返回

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
    });

模板参数

EventIdType – Type of the event identifier (enum)

参数
  • event_id – Event identifier

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

返回

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.

模板参数

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

参数

result[in] std::expected object

返回

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();

模板参数

EventIdValue – The specific EventId enum value to monitor

Public Functions

inline bool start()

Start monitoring for events.

返回

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.

参数
  • expected_items – The expected items to find

  • timeout_ms – Maximum time to wait in milliseconds

返回

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.

参数

timeout_ms – Maximum time to wait in milliseconds

返回

true if any event was received, false on timeout

inline size_t get_count() const

Get the number of received events.

返回

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

inline bool has(const ReceivedItmes &expected_items) const

Check if specific items have been received.

参数

expected_items – The expected items to find

返回

true if matching items exists in received items

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

Get all received events (unfiltered)

返回

Copy of all received events

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

Get the last received event.

返回

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
}

模板参数

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

返回

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());
}

模板参数

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

返回

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.

返回

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())

参数
  • 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))

参数
  • 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))

参数
  • 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))

参数
  • 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