Event Service

Last Updated on : 2024-01-09 03:45:59download

This topic describes the TuyaOS event service.

Overview

Concepts

TuyaOS event is a lightweight event notification library. It features:

  • Flexible publish/subscribe messaging allows publishers to publish data to any topic from anywhere at any time.
  • Lightweight event notification inside the process, with about 400 lines of code.
  • The library can run on any platform thanks to the cross-platform feature of the TuyaOS.
  • Events called synchronously by default. The cross-platform feature enables the use of a job queue in the subscribed function to achieve an asynchronous mechanism.

Features

The publish-subscribe pattern allows service modules to be decoupled, enabling you to subscribe to system startup and network events. You can send events in the order of subscription, prioritize emergent events, and perform one-time delivery.

How it works

ty_subscribe_eventty_publish_eventPoll the event linked list. A name is matched.Poll the event linked list. A name is matched.The handler callback for the subscribed event, which stores the subscription linked list included in the linked list struct of the respective event.Poll the subscription linked list in the event linked list.Return data after polling nodes.If the node name is matched, invoke the callback of the subscribed node to pass data.Poll the event linked list. A name is not matched.Poll the event linked list. A name is not matched.Add the subscribed event to the inactive subscription linked list.Create an event node, with the subscription linked list already existing.Poll the subscription linked list in the inactive event linked list.Return data after polling nodes.If a name is matched, add the event to the subscription linked list of the event struct.Invoke the subscription linked list member callback in the event linked list to sync data.ty_subscribe_eventty_publish_event

Development guide

Runtime environment

As a standard feature offered by the Wi-Fi Development Framework, the event service can be run without any special requirement.

Type definition

#define EVENT_NAME_MAX_LEN (16)  // move to tuya_iot_config.h. use kconfig config. default is 16

/**
 * @brief max length of event description
 *
 */
#define EVENT_DESC_MAX_LEN (32)

/**
 * @brief subscriber type
 *
 */
typedef BYTE_T SUBSCRIBE_TYPE_E;

#define SUBSCRIBE_TYPE_NORMAL    0  // normal type, dispatch by the subscribe order, remove when unsubscribe

#define SUBSCRIBE_TYPE_EMERGENCY 1  // emergency type, dispatch first, remove when unsubscribe

#define SUBSCRIBE_TYPE_ONETIME   2  // one time type, dispatch by the subscribe order, remove after first time dispath

  • EVENT_NAME_MAX_LEN: The maximum length of the event name, defaulting to 16 bytes.

  • EVENT_DESC_MAX_LEN: The maximum length of the event description, defaulting to 32 bytes.

  • SUBSCRIBE_TYPE_E: The subscription type.

    • SUBSCRIBE_TYPE_NORMAL: The common type. Events are sent in the order of subscription and deleted when unsubscribing.

    • SUBSCRIBE_TYPE_EMERGENCY: The emergent type. Events are prioritized for sending and deleted when unsubscribing.

    • SUBSCRIBE_TYPE_ONETIME: One-time type. Events are sent in the order of subscription and deleted upon sending.

Callback

/**
* @brief event subscribe callback function type
*
*/
typedef INT_T(*EVENT_SUBSCRIBE_CB)(VOID_T *data);

API description

Publish an event

/**
 * @brief: publish event
 *
 * @param[in] name: event name
 * @param[in] data: event data
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET ty_publish_event(CONST CHAR_T* name, VOID_T *data);

Publish an event notification, including the event data, to inform all subscribers for further processing. To publish an event, you need to check whether this event has been created.

  • If it has not been created, it means that the same event has not been published before. However, there might be its subscribers staged in free_subscribe_root. Therefore, the subscriber will be retrieved from free_subscribe_root. After the subscriber is found from free_subscribe_root, it will be mounted to the event’s subscribe_root before event publishing.

  • If the event has been created, it means that the same event has been published before, and all subscribers have been processed. The event can be published directly, without the need to retrieve subscribers from free_subscribe_root.

  • Retrieve the event’s subscribe_root and publish the event data to each subscriber. Call the subscriber callback, determine its return value, and record it. If the event has no subscribers, it will not be published, with no resource created.

Subscribe to an event

/**
 * @brief: subscribe event
 *
 * @param[in] name: event name
 * @param[in] desc: subscribe description
 * @param[in] cb: subscribe callback function
 * @param[in] type: subscribe type
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
int ty_subscribe_event(const char *name, const char *desc, const event_subscribe_cb cb, SUBSCRIBE_TYPE_E type);

Subscribe to an event, including the event name, purpose, and callback. To subscribe to an event, you need to check whether this event has been created.

  • If it has not been created, stage the subscriber to free_subscribe_root.
  • If it has been created, mount the subscriber to the event’s subscribe_root.

Subscribing to an event does not retrieve its previous state, because staging data requires significant resources and is unnecessary.

Unsubscribe from an event

/**
 * @brief: unsubscribe event
 *
 * @param[in] name: event name
 * @param[in] desc: subscribe description
 * @param[in] cb: subscribe callback function
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
int ty_unsubscribe_event(const char *name, const char *desc, event_subscribe_cb cb);

Unsubscribe to an event, including the event name, purpose, and callback. If the subscriber is not bound with an event, remove it from free_subscribe_root.

If the subscriber is bound with an event and is the last one, remove it from the event’s subscribe_root and destroy this event. Otherwise, you only need to remove the subscriber from the event’s subscribe_root.

Example

#define EVENT_SAMPLE "publish.sample"
OPERATE_RET sample_subcribe_cb(event_data_t *raw_data)
{
    event_data_t *data = (event_data_t*)raw_data;

    TAL_PR_DEBUG("recv event");
    return OPRT_OK;
}

OPERATE_RET sample_subcribe_emergence_cb(event_data_t *raw_data)
{
    event_data_t *data = (event_data_t*)raw_data;

    TAL_PR_DEBUG("recv event emergence");
    return OPRT_OK;
}

OPERATE_RET sample_subcribe_onetime_cb(event_data_t *raw_data)
{
    event_data_t *data = (event_data_t*)raw_data;

    TAL_PR_DEBUG("recv event emergence");
    return OPRT_OK;
}

OPERATE_RET sample_event()
{
    OPERATE_RET rt = OPRT_OK;

     // For event publishing, if an event has no subscribers, it will not be published.
    rt = ty_publish_event(EVENT_SAMPLE, NULL);
    EXPECT_EQ(rt, OPRT_OK);

    // Subscribe to an event.
    char desc[] = "subscribe.sample";
    rt = ty_subscribe_event(EVENT_SAMPLE, desc, sample_subcribe_cb, EVENT_TYPE_NORMAL);
    EXPECT_EQ(rt, OPRT_OK);

    // Publish an event.
    rt = ty_publish_event(EVENT_SAMPLE, NULL);
    EXPECT_EQ(rt, OPRT_OK);

    // Subscribe to an emergent event.
    rt = ty_subscribe_event(EVENT_SAMPLE, desc, sample_subcribe_emergence_cb,                                         SUBSCRIBE_TYPE_EMERGENCY);
    EXPECT_EQ(rt, OPRT_OK);

    // Unsubscribe from an emergent event.
    rt = ty_unsubscribe_event(EVENT_SAMPLE, desc, sample_subcribe_emergence_cb);
    EXPECT_EQ(rt, OPRT_OK);

    // Subscribe to a one-time event, which does not require manual unsubscription.
    rt = ty_subscribe_event(EVENT_SAMPLE, desc, sample_subcribe_onetime_cb,                                         EVENT_TYPE_ONETIME);
    EXPECT_EQ(rt, OPRT_OK);

    // Publish an event.
    rt = ty_publish_event(EVENT_SAMPLE, NULL);
    EXPECT_EQ(rt, OPRT_OK);

     // Unsubscribe from an event. If an event has no subscribers, it will be destroyed.
    rt = ty_unsubscribe_event(EVENT_SAMPLE, desc, sample_subcribe_cb);
    EXPECT_EQ(rt, OPRT_OK);

    return OPRT_OK;
}