diff --git a/libraries/Network/src/NetworkEvents.cpp b/libraries/Network/src/NetworkEvents.cpp
index bb02282e9b3..5a7e7c49afa 100644
--- a/libraries/Network/src/NetworkEvents.cpp
+++ b/libraries/Network/src/NetworkEvents.cpp
@@ -8,28 +8,6 @@
 #include "esp_task.h"
 #include "esp32-hal.h"
 
-typedef struct NetworkEventCbList {
-  static network_event_handle_t current_id;
-  network_event_handle_t id;
-  NetworkEventCb cb;
-  NetworkEventFuncCb fcb;
-  NetworkEventSysCb scb;
-  arduino_event_id_t event;
-
-  NetworkEventCbList() : id(current_id++), cb(NULL), fcb(NULL), scb(NULL), event(ARDUINO_EVENT_NONE) {}
-} NetworkEventCbList_t;
-network_event_handle_t NetworkEventCbList::current_id = 1;
-
-// arduino dont like std::vectors move static here
-static std::vector<NetworkEventCbList_t> cbEventList;
-
-static void _network_event_task(void *arg) {
-  for (;;) {
-    ((NetworkEvents *)arg)->checkForEvent();
-  }
-  vTaskDelete(NULL);
-}
-
 NetworkEvents::NetworkEvents() : _arduino_event_group(NULL), _arduino_event_queue(NULL), _arduino_event_task_handle(NULL) {}
 
 NetworkEvents::~NetworkEvents() {
@@ -43,8 +21,9 @@ NetworkEvents::~NetworkEvents() {
   }
   if (_arduino_event_queue != NULL) {
     arduino_event_t *event = NULL;
+    // consume queue
     while (xQueueReceive(_arduino_event_queue, &event, 0) == pdTRUE) {
-      free(event);
+      delete event;
     }
     vQueueDelete(_arduino_event_queue);
     _arduino_event_queue = NULL;
@@ -78,7 +57,14 @@ bool NetworkEvents::initNetworkEvents() {
   }
 
   if (!_arduino_event_task_handle) {
-    xTaskCreateUniversal(_network_event_task, "arduino_events", 4096, this, ESP_TASKD_EVENT_PRIO - 1, &_arduino_event_task_handle, ARDUINO_EVENT_RUNNING_CORE);
+    xTaskCreateUniversal(
+      [](void *self) {
+        static_cast<NetworkEvents *>(self)->_checkForEvent();
+      },
+      "arduino_events",  // label
+      4096,              // event task's stack size
+      this, ESP_TASKD_EVENT_PRIO - 1, &_arduino_event_task_handle, ARDUINO_EVENT_RUNNING_CORE
+    );
     if (!_arduino_event_task_handle) {
       log_e("Network Event Task Start Failed!");
       return false;
@@ -88,66 +74,76 @@ bool NetworkEvents::initNetworkEvents() {
   return true;
 }
 
-bool NetworkEvents::postEvent(arduino_event_t *data) {
+bool NetworkEvents::postEvent(const arduino_event_t *data) {
   if (data == NULL || _arduino_event_queue == NULL) {
     return false;
   }
-  arduino_event_t *event = (arduino_event_t *)malloc(sizeof(arduino_event_t));
+  arduino_event_t *event = new arduino_event_t();
   if (event == NULL) {
     log_e("Arduino Event Malloc Failed!");
     return false;
   }
+
   memcpy(event, data, sizeof(arduino_event_t));
   if (xQueueSend(_arduino_event_queue, &event, portMAX_DELAY) != pdPASS) {
     log_e("Arduino Event Send Failed!");
+    delete event;  // release mem on error
     return false;
   }
   return true;
 }
 
-void NetworkEvents::checkForEvent() {
-  arduino_event_t *event = NULL;
+void NetworkEvents::_checkForEvent() {
+  // this task can't run without the queue
   if (_arduino_event_queue == NULL) {
+    _arduino_event_task_handle = NULL;
+    vTaskDelete(NULL);
     return;
   }
-  if (xQueueReceive(_arduino_event_queue, &event, portMAX_DELAY) != pdTRUE) {
-    return;
-  }
-  if (event == NULL) {
-    return;
-  }
-  log_v("Network Event: %d - %s", event->event_id, eventName(event->event_id));
-  for (uint32_t i = 0; i < cbEventList.size(); i++) {
-    NetworkEventCbList_t entry = cbEventList[i];
-    if (entry.cb || entry.fcb || entry.scb) {
-      if (entry.event == (arduino_event_id_t)event->event_id || entry.event == ARDUINO_EVENT_MAX) {
-        if (entry.cb) {
-          entry.cb((arduino_event_id_t)event->event_id);
-        } else if (entry.fcb) {
-          entry.fcb((arduino_event_id_t)event->event_id, (arduino_event_info_t)event->event_info);
-        } else {
-          entry.scb(event);
+
+  for (;;) {
+    arduino_event_t *event = NULL;
+    // wait for an event on a queue
+    if (xQueueReceive(_arduino_event_queue, &event, portMAX_DELAY) != pdTRUE) {
+      continue;
+    }
+    if (event == NULL) {
+      continue;
+    }
+    log_v("Network Event: %d - %s", event->event_id, eventName(event->event_id));
+
+#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
+    std::unique_lock<std::mutex> lock(_mtx);
+#endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
+
+    // iterate over registered callbacks
+    for (auto &i : _cbEventList) {
+      if (i.cb || i.fcb || i.scb) {
+        if (i.event == (arduino_event_id_t)event->event_id || i.event == ARDUINO_EVENT_MAX) {
+          if (i.cb) {
+            i.cb((arduino_event_id_t)event->event_id);
+            continue;
+          }
+
+          if (i.fcb) {
+            i.fcb((arduino_event_id_t)event->event_id, (arduino_event_info_t)event->event_info);
+            continue;
+          }
+
+          i.scb(event);
         }
       }
     }
-  }
-  free(event);
-}
 
-uint32_t NetworkEvents::findEvent(NetworkEventCb cbEvent, arduino_event_id_t event) {
-  uint32_t i;
+#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
+    lock.unlock();
+#endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
 
-  if (!cbEvent) {
-    return cbEventList.size();
+    // release the event object's memory
+    delete event;
   }
 
-  for (i = 0; i < cbEventList.size(); i++) {
-    NetworkEventCbList_t entry = cbEventList[i];
-    if (entry.cb == cbEvent && entry.event == event) {
-      break;
-    }
-  }
-  return i;
+  vTaskDelete(NULL);
 }
 
 template<typename T, typename... U> static size_t getStdFunctionAddress(std::function<T(U...)> f) {
@@ -159,55 +155,17 @@ template<typename T, typename... U> static size_t getStdFunctionAddress(std::fun
   return (size_t)fnPointer;
 }
 
-uint32_t NetworkEvents::findEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event) {
-  uint32_t i;
-
-  if (!cbEvent) {
-    return cbEventList.size();
-  }
-
-  for (i = 0; i < cbEventList.size(); i++) {
-    NetworkEventCbList_t entry = cbEventList[i];
-    if (getStdFunctionAddress(entry.fcb) == getStdFunctionAddress(cbEvent) && entry.event == event) {
-      break;
-    }
-  }
-  return i;
-}
-
-uint32_t NetworkEvents::findEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event) {
-  uint32_t i;
-
-  if (!cbEvent) {
-    return cbEventList.size();
-  }
-
-  for (i = 0; i < cbEventList.size(); i++) {
-    NetworkEventCbList_t entry = cbEventList[i];
-    if (entry.scb == cbEvent && entry.event == event) {
-      break;
-    }
-  }
-  return i;
-}
-
 network_event_handle_t NetworkEvents::onEvent(NetworkEventCb cbEvent, arduino_event_id_t event) {
   if (!cbEvent) {
     return 0;
   }
 
-  if (findEvent(cbEvent, event) < cbEventList.size()) {
-    log_w("Attempt to add duplicate event handler!");
-    return 0;
-  }
+#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
+  std::lock_guard<std::mutex> lock(_mtx);
+#endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
 
-  NetworkEventCbList_t newEventHandler;
-  newEventHandler.cb = cbEvent;
-  newEventHandler.fcb = NULL;
-  newEventHandler.scb = NULL;
-  newEventHandler.event = event;
-  cbEventList.push_back(newEventHandler);
-  return newEventHandler.id;
+  _cbEventList.emplace_back(++_current_id, cbEvent, nullptr, nullptr, event);
+  return _cbEventList.back().id;
 }
 
 network_event_handle_t NetworkEvents::onEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event) {
@@ -215,18 +173,12 @@ network_event_handle_t NetworkEvents::onEvent(NetworkEventFuncCb cbEvent, arduin
     return 0;
   }
 
-  if (findEvent(cbEvent, event) < cbEventList.size()) {
-    log_w("Attempt to add duplicate event handler!");
-    return 0;
-  }
+#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
+  std::lock_guard<std::mutex> lock(_mtx);
+#endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
 
-  NetworkEventCbList_t newEventHandler;
-  newEventHandler.cb = NULL;
-  newEventHandler.fcb = cbEvent;
-  newEventHandler.scb = NULL;
-  newEventHandler.event = event;
-  cbEventList.push_back(newEventHandler);
-  return newEventHandler.id;
+  _cbEventList.emplace_back(++_current_id, nullptr, cbEvent, nullptr, event);
+  return _cbEventList.back().id;
 }
 
 network_event_handle_t NetworkEvents::onEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event) {
@@ -234,18 +186,12 @@ network_event_handle_t NetworkEvents::onEvent(NetworkEventSysCb cbEvent, arduino
     return 0;
   }
 
-  if (findEvent(cbEvent, event) < cbEventList.size()) {
-    log_w("Attempt to add duplicate event handler!");
-    return 0;
-  }
+#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
+  std::lock_guard<std::mutex> lock(_mtx);
+#endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
 
-  NetworkEventCbList_t newEventHandler;
-  newEventHandler.cb = NULL;
-  newEventHandler.fcb = NULL;
-  newEventHandler.scb = cbEvent;
-  newEventHandler.event = event;
-  cbEventList.push_back(newEventHandler);
-  return newEventHandler.id;
+  _cbEventList.emplace_back(++_current_id, nullptr, nullptr, cbEvent, event);
+  return _cbEventList.back().id;
 }
 
 network_event_handle_t NetworkEvents::onSysEvent(NetworkEventCb cbEvent, arduino_event_id_t event) {
@@ -253,18 +199,12 @@ network_event_handle_t NetworkEvents::onSysEvent(NetworkEventCb cbEvent, arduino
     return 0;
   }
 
-  if (findEvent(cbEvent, event) < cbEventList.size()) {
-    log_w("Attempt to add duplicate event handler!");
-    return 0;
-  }
+#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
+  std::lock_guard<std::mutex> lock(_mtx);
+#endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
 
-  NetworkEventCbList_t newEventHandler;
-  newEventHandler.cb = cbEvent;
-  newEventHandler.fcb = NULL;
-  newEventHandler.scb = NULL;
-  newEventHandler.event = event;
-  cbEventList.insert(cbEventList.begin(), newEventHandler);
-  return newEventHandler.id;
+  _cbEventList.emplace(_cbEventList.begin(), ++_current_id, cbEvent, nullptr, nullptr, event);
+  return _cbEventList.front().id;
 }
 
 network_event_handle_t NetworkEvents::onSysEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event) {
@@ -272,18 +212,12 @@ network_event_handle_t NetworkEvents::onSysEvent(NetworkEventFuncCb cbEvent, ard
     return 0;
   }
 
-  if (findEvent(cbEvent, event) < cbEventList.size()) {
-    log_w("Attempt to add duplicate event handler!");
-    return 0;
-  }
+#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
+  std::lock_guard<std::mutex> lock(_mtx);
+#endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
 
-  NetworkEventCbList_t newEventHandler;
-  newEventHandler.cb = NULL;
-  newEventHandler.fcb = cbEvent;
-  newEventHandler.scb = NULL;
-  newEventHandler.event = event;
-  cbEventList.insert(cbEventList.begin(), newEventHandler);
-  return newEventHandler.id;
+  _cbEventList.emplace(_cbEventList.begin(), ++_current_id, nullptr, cbEvent, nullptr, event);
+  return _cbEventList.front().id;
 }
 
 network_event_handle_t NetworkEvents::onSysEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event) {
@@ -291,77 +225,88 @@ network_event_handle_t NetworkEvents::onSysEvent(NetworkEventSysCb cbEvent, ardu
     return 0;
   }
 
-  if (findEvent(cbEvent, event) < cbEventList.size()) {
-    log_w("Attempt to add duplicate event handler!");
-    return 0;
-  }
+#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
+  std::lock_guard<std::mutex> lock(_mtx);
+#endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
 
-  NetworkEventCbList_t newEventHandler;
-  newEventHandler.cb = NULL;
-  newEventHandler.fcb = NULL;
-  newEventHandler.scb = cbEvent;
-  newEventHandler.event = event;
-  cbEventList.insert(cbEventList.begin(), newEventHandler);
-  return newEventHandler.id;
+  _cbEventList.emplace(_cbEventList.begin(), ++_current_id, nullptr, nullptr, cbEvent, event);
+  return _cbEventList.front().id;
 }
 
 void NetworkEvents::removeEvent(NetworkEventCb cbEvent, arduino_event_id_t event) {
-  uint32_t i;
-
   if (!cbEvent) {
     return;
   }
 
-  i = findEvent(cbEvent, event);
-  if (i >= cbEventList.size()) {
-    log_w("Event handler not found!");
-    return;
-  }
+#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
+  std::lock_guard<std::mutex> lock(_mtx);
+#endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
 
-  cbEventList.erase(cbEventList.begin() + i);
+  _cbEventList.erase(
+    std::remove_if(
+      _cbEventList.begin(), _cbEventList.end(),
+      [cbEvent, event](const NetworkEventCbList_t &e) {
+        return e.cb == cbEvent && e.event == event;
+      }
+    ),
+    _cbEventList.end()
+  );
 }
 
 void NetworkEvents::removeEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event) {
-  uint32_t i;
-
   if (!cbEvent) {
     return;
   }
 
-  i = findEvent(cbEvent, event);
-  if (i >= cbEventList.size()) {
-    log_w("Event handler not found!");
-    return;
-  }
+#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
+  std::lock_guard<std::mutex> lock(_mtx);
+#endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
 
-  cbEventList.erase(cbEventList.begin() + i);
+  _cbEventList.erase(
+    std::remove_if(
+      _cbEventList.begin(), _cbEventList.end(),
+      [cbEvent, event](const NetworkEventCbList_t &e) {
+        return getStdFunctionAddress(e.fcb) == getStdFunctionAddress(cbEvent) && e.event == event;
+      }
+    ),
+    _cbEventList.end()
+  );
 }
 
 void NetworkEvents::removeEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event) {
-  uint32_t i;
-
   if (!cbEvent) {
     return;
   }
 
-  i = findEvent(cbEvent, event);
-  if (i >= cbEventList.size()) {
-    log_w("Event handler not found!");
-    return;
-  }
+#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
+  std::lock_guard<std::mutex> lock(_mtx);
+#endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
 
-  cbEventList.erase(cbEventList.begin() + i);
+  _cbEventList.erase(
+    std::remove_if(
+      _cbEventList.begin(), _cbEventList.end(),
+      [cbEvent, event](const NetworkEventCbList_t &e) {
+        return e.scb == cbEvent && e.event == event;
+      }
+    ),
+    _cbEventList.end()
+  );
 }
 
 void NetworkEvents::removeEvent(network_event_handle_t id) {
-  for (uint32_t i = 0; i < cbEventList.size(); i++) {
-    NetworkEventCbList_t entry = cbEventList[i];
-    if (entry.id == id) {
-      cbEventList.erase(cbEventList.begin() + i);
-      return;
-    }
-  }
-  log_w("Event handler not found!");
+#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
+  std::lock_guard<std::mutex> lock(_mtx);
+#endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
+
+  _cbEventList.erase(
+    std::remove_if(
+      _cbEventList.begin(), _cbEventList.end(),
+      [id](const NetworkEventCbList_t &e) {
+        return e.id == id;
+      }
+    ),
+    _cbEventList.end()
+  );
 }
 
 int NetworkEvents::setStatusBits(int bits) {
@@ -380,7 +325,7 @@ int NetworkEvents::clearStatusBits(int bits) {
   return xEventGroupClearBits(_arduino_event_group, bits);
 }
 
-int NetworkEvents::getStatusBits() {
+int NetworkEvents::getStatusBits() const {
   if (!_arduino_event_group) {
     return _initial_bits;
   }
diff --git a/libraries/Network/src/NetworkEvents.h b/libraries/Network/src/NetworkEvents.h
index ac324d19841..e134d6816a2 100644
--- a/libraries/Network/src/NetworkEvents.h
+++ b/libraries/Network/src/NetworkEvents.h
@@ -16,6 +16,9 @@
 #include "freertos/queue.h"
 #include "freertos/semphr.h"
 #include "freertos/event_groups.h"
+#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
+#include <mutex>
+#endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
 
 #if SOC_WIFI_SUPPORTED
 #include "esp_wifi_types.h"
@@ -24,8 +27,8 @@
 #endif
 
 #if SOC_WIFI_SUPPORTED
-static const int WIFI_SCANNING_BIT = BIT0;
-static const int WIFI_SCAN_DONE_BIT = BIT1;
+constexpr int WIFI_SCANNING_BIT = BIT0;
+constexpr int WIFI_SCAN_DONE_BIT = BIT1;
 #endif
 
 #define NET_HAS_IP6_GLOBAL_BIT 0
@@ -33,7 +36,7 @@ static const int WIFI_SCAN_DONE_BIT = BIT1;
 ESP_EVENT_DECLARE_BASE(ARDUINO_EVENTS);
 
 typedef enum {
-  ARDUINO_EVENT_NONE,
+  ARDUINO_EVENT_NONE = 0,
   ARDUINO_EVENT_ETH_START,
   ARDUINO_EVENT_ETH_STOP,
   ARDUINO_EVENT_ETH_CONNECTED,
@@ -42,10 +45,11 @@ typedef enum {
   ARDUINO_EVENT_ETH_LOST_IP,
   ARDUINO_EVENT_ETH_GOT_IP6,
 #if SOC_WIFI_SUPPORTED
-  ARDUINO_EVENT_WIFI_OFF,
+  ARDUINO_EVENT_WIFI_OFF = 100,
   ARDUINO_EVENT_WIFI_READY,
   ARDUINO_EVENT_WIFI_SCAN_DONE,
-  ARDUINO_EVENT_WIFI_STA_START,
+  ARDUINO_EVENT_WIFI_FTM_REPORT,
+  ARDUINO_EVENT_WIFI_STA_START = 110,
   ARDUINO_EVENT_WIFI_STA_STOP,
   ARDUINO_EVENT_WIFI_STA_CONNECTED,
   ARDUINO_EVENT_WIFI_STA_DISCONNECTED,
@@ -53,24 +57,23 @@ typedef enum {
   ARDUINO_EVENT_WIFI_STA_GOT_IP,
   ARDUINO_EVENT_WIFI_STA_GOT_IP6,
   ARDUINO_EVENT_WIFI_STA_LOST_IP,
-  ARDUINO_EVENT_WIFI_AP_START,
+  ARDUINO_EVENT_WIFI_AP_START = 130,
   ARDUINO_EVENT_WIFI_AP_STOP,
   ARDUINO_EVENT_WIFI_AP_STACONNECTED,
   ARDUINO_EVENT_WIFI_AP_STADISCONNECTED,
   ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED,
   ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED,
   ARDUINO_EVENT_WIFI_AP_GOT_IP6,
-  ARDUINO_EVENT_WIFI_FTM_REPORT,
-  ARDUINO_EVENT_WPS_ER_SUCCESS,
+  ARDUINO_EVENT_WPS_ER_SUCCESS = 140,
   ARDUINO_EVENT_WPS_ER_FAILED,
   ARDUINO_EVENT_WPS_ER_TIMEOUT,
   ARDUINO_EVENT_WPS_ER_PIN,
   ARDUINO_EVENT_WPS_ER_PBC_OVERLAP,
-  ARDUINO_EVENT_SC_SCAN_DONE,
+  ARDUINO_EVENT_SC_SCAN_DONE = 150,
   ARDUINO_EVENT_SC_FOUND_CHANNEL,
   ARDUINO_EVENT_SC_GOT_SSID_PSWD,
   ARDUINO_EVENT_SC_SEND_ACK_DONE,
-  ARDUINO_EVENT_PROV_INIT,
+  ARDUINO_EVENT_PROV_INIT = 160,
   ARDUINO_EVENT_PROV_DEINIT,
   ARDUINO_EVENT_PROV_START,
   ARDUINO_EVENT_PROV_END,
@@ -78,7 +81,7 @@ typedef enum {
   ARDUINO_EVENT_PROV_CRED_FAIL,
   ARDUINO_EVENT_PROV_CRED_SUCCESS,
 #endif
-  ARDUINO_EVENT_PPP_START,
+  ARDUINO_EVENT_PPP_START = 200,
   ARDUINO_EVENT_PPP_STOP,
   ARDUINO_EVENT_PPP_CONNECTED,
   ARDUINO_EVENT_PPP_DISCONNECTED,
@@ -110,36 +113,123 @@ typedef union {
 #endif
 } arduino_event_info_t;
 
-typedef struct {
+/**
+ * @brief struct combines arduino event id and event's data object
+ *
+ */
+struct arduino_event_t {
   arduino_event_id_t event_id;
   arduino_event_info_t event_info;
-} arduino_event_t;
-
-typedef void (*NetworkEventCb)(arduino_event_id_t event);
-typedef std::function<void(arduino_event_id_t event, arduino_event_info_t info)> NetworkEventFuncCb;
-typedef void (*NetworkEventSysCb)(arduino_event_t *event);
+};
 
-typedef size_t network_event_handle_t;
+// type aliases
+using NetworkEventCb = void (*)(arduino_event_id_t event);
+using NetworkEventFuncCb = std::function<void(arduino_event_id_t event, arduino_event_info_t info)>;
+using NetworkEventSysCb = void (*)(arduino_event_t *event);
+using network_event_handle_t = size_t;
 
+/**
+ * @brief Class that provides network events callback handling
+ * it registers user callback functions for event handling,
+ * maintains the queue of events and propagates the event among subscribed callbacks
+ * callback are called in the context of a dedicated task consuming the queue
+ *
+ */
 class NetworkEvents {
 public:
   NetworkEvents();
   ~NetworkEvents();
 
+  /**
+   * @brief register callback function to be executed on arduino event(s)
+   * @note if same handler is registered twice or more than same handler would be called twice or more times
+   *
+   * @param cbEvent static callback function
+   * @param event event to process, any event by default
+   * @return network_event_handle_t
+   */
   network_event_handle_t onEvent(NetworkEventCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);
+
+  /**
+   * @brief register functional callback to be executed on arduino event(s)
+   * also used for lambda callbacks
+   * @note if same handler is registered twice or more than same handler would be called twice or more times
+   *
+   * @param cbEvent static callback function
+   * @param event event to process, any event by default
+   * @return network_event_handle_t
+   */
   network_event_handle_t onEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);
+
+  /**
+   * @brief register static system callback to be executed on arduino event(s)
+   * callback function would be supplied with a pointer to arduino_event_t structure as an argument
+   *
+   * @note if same handler is registered twice or more than same handler would be called twice or more times
+   *
+   * @param cbEvent static callback function
+   * @param event event to process, any event by default
+   * @return network_event_handle_t
+   */
   network_event_handle_t onEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);
+
+  /**
+   * @brief unregister static function callback
+   * @note a better way to unregister callbacks is to save/unregister via network_event_handle_t
+   *
+   * @param cbEvent static callback function
+   * @param event event to process, any event by default
+   */
   void removeEvent(NetworkEventCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);
-  void removeEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);
+
+  /**
+   * @brief unregister functional callback
+   * @note a better way to unregister callbacks is to save/unregister via network_event_handle_t
+   * @note this does not work for lambda's! Do unregister via network_event_handle_t
+   *
+   * @param cbEvent functional callback
+   * @param event event to process, any event by default
+   */
+  void removeEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX)
+    __attribute__((deprecated("removing functional callbacks via pointer is deprecated, use removeEvent(network_event_handle_t) instead")));
+
+  /**
+   * @brief unregister static system function callback
+   * @note a better way to unregister callbacks is to save/unregister via network_event_handle_t
+   *
+   * @param cbEvent static callback function
+   * @param event event to process, any event by default
+   */
   void removeEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);
+
+  /**
+   * @brief unregister event callback via handler
+   *
+   * @param cbEvent static callback function
+   * @param event event to process, any event by default
+   */
   void removeEvent(network_event_handle_t event_handle);
 
-  const char *eventName(arduino_event_id_t id);
+  /**
+   * @brief get a human-readable name of an event by it's id
+   *
+   * @param id event id code
+   * @return const char* event name string
+   */
+  static const char *eventName(arduino_event_id_t id);
 
-  void checkForEvent();
-  bool postEvent(arduino_event_t *event);
+  /**
+   * @brief post an event to the queue
+   * and propagade and event to subscribed handlers
+   * @note posting an event will trigger context switch from a lower priority task
+   *
+   * @param event a pointer to arduino_event_t struct
+   * @return true if event was queued susccessfuly
+   * @return false on memrory allocation error or queue is full
+   */
+  bool postEvent(const arduino_event_t *event);
 
-  int getStatusBits();
+  int getStatusBits() const;
   int waitStatusBits(int bits, uint32_t timeout_ms);
   int setStatusBits(int bits);
   int clearStatusBits(int bits);
@@ -155,15 +245,53 @@ class NetworkEvents {
 
 protected:
   bool initNetworkEvents();
-  uint32_t findEvent(NetworkEventCb cbEvent, arduino_event_id_t event);
-  uint32_t findEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event);
-  uint32_t findEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event);
+  // same as onEvent() but places newly added handler at the beginning of registered events list
   network_event_handle_t onSysEvent(NetworkEventCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);
+  // same as onEvent() but places newly added handler at the beginning of registered events list
   network_event_handle_t onSysEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);
+  // same as onEvent() but places newly added handler at the beginning of registered events list
   network_event_handle_t onSysEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);
 
 private:
+  /**
+   * @brief an object holds callback's definitions:
+   * - callback id
+   * - callback function pointers
+   * - binded event id
+   *
+   */
+  struct NetworkEventCbList_t {
+    network_event_handle_t id;
+    NetworkEventCb cb;
+    NetworkEventFuncCb fcb;
+    NetworkEventSysCb scb;
+    arduino_event_id_t event;
+
+    explicit NetworkEventCbList_t(
+      network_event_handle_t id, NetworkEventCb cb = nullptr, NetworkEventFuncCb fcb = nullptr, NetworkEventSysCb scb = nullptr,
+      arduino_event_id_t event = ARDUINO_EVENT_MAX
+    )
+      : id(id), cb(cb), fcb(fcb), scb(scb), event(event) {}
+  };
+
+  // define initial id's value
+  network_event_handle_t _current_id{0};
+
   EventGroupHandle_t _arduino_event_group;
   QueueHandle_t _arduino_event_queue;
   TaskHandle_t _arduino_event_task_handle;
+
+  // registered events callbacks container
+  std::vector<NetworkEventCbList_t> _cbEventList;
+
+#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1
+  // container access mutex
+  std::mutex _mtx;
+#endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
+
+  /**
+   * @brief task function that picks events from an event queue and calls registered callbacks
+   *
+   */
+  void _checkForEvent();
 };