diff --git a/vehicle/OVMS.V3/main/Kconfig b/vehicle/OVMS.V3/main/Kconfig
index 54ac004c..06880684 100644
--- a/vehicle/OVMS.V3/main/Kconfig
+++ b/vehicle/OVMS.V3/main/Kconfig
@@ -63,7 +63,8 @@ config OVMS_HW_ASYNC_QUEUE_SIZE
 
 config OVMS_HW_EVENT_QUEUE_SIZE
     int "EVENT queue size"
-    default 20
+    range 80 200
+    default 100
     depends on OVMS
     help
         The size of the EVENT queue.
diff --git a/vehicle/OVMS.V3/main/ovms_events.cpp b/vehicle/OVMS.V3/main/ovms_events.cpp
index b758eae3..09aadb5f 100644
--- a/vehicle/OVMS.V3/main/ovms_events.cpp
+++ b/vehicle/OVMS.V3/main/ovms_events.cpp
@@ -51,9 +51,14 @@ static const char *TAG = "events";
 #include "ovms_ota.h"
 #endif
 
+#if CONFIG_OVMS_HW_EVENT_QUEUE_SIZE < 80
+#error "CONFIG ERROR: OVMS_HW_EVENT_QUEUE_SIZE needs to be >= 80"
+#endif
+
 OvmsEvents MyEvents __attribute__ ((init_priority (1200)));
 
 typedef void (*event_signal_done_fn)(const char* event, void* data);
+static void CheckQueueOverflow(const char* from, char* event);
 
 bool EventMap::GetCompletion(OvmsWriter* writer, const char* token) const
   {
@@ -257,6 +262,12 @@ void OvmsEvents::EventTask()
         {
         case EVENT_none:
           break;
+        case EVENT_addhandler:
+          HandleQueueAddHandler(&msg);
+          break;
+        case EVENT_removehandlers:
+          HandleQueueRemoveHandlers(&msg);
+          break;
         case EVENT_signal:
           m_current_event = msg.body.signal.event;
           HandleQueueSignalEvent(&msg);
@@ -297,38 +308,50 @@ void OvmsEvents::HandleQueueSignalEvent(event_queue_t* msg)
       ESP_LOGD(TAG, "Signal(%s)",m_current_event.c_str());
     }
 
-  auto k = m_map.find(m_current_event);
-  if (k != m_map.end())
+  // Run callbacks:
     {
-    EventCallbackList* el = k->second;
-    if (el)
+    OvmsRecMutexLock lock(&m_map_mutex);
+
+    auto k = m_map.find(m_current_event);
+    if (k != m_map.end())
       {
-      for (EventCallbackList::iterator itc=el->begin(); itc!=el->end(); ++itc)
+      EventCallbackList* el = k->second;
+      if (el)
         {
-        m_current_started = monotonictime;
-        m_current_callback = *itc;
-        m_current_callback->m_callback(m_current_event, msg->body.signal.data);
-        m_current_callback = NULL;
+        for (EventCallbackList::iterator itc=el->begin(); itc!=el->end(); ++itc)
+          {
+          m_current_started = monotonictime;
+          m_current_callback = *itc;
+          if (m_current_callback->m_callback)
+            {
+            m_current_callback->m_callback(m_current_event, msg->body.signal.data);
+            }
+          m_current_callback = NULL;
+          }
         }
       }
-    }
 
-  k = m_map.find("*");
-  if (k != m_map.end())
-    {
-    EventCallbackList* el = k->second;
-    if (el)
+    k = m_map.find("*");
+    if (k != m_map.end())
       {
-      for (EventCallbackList::iterator itc=el->begin(); itc!=el->end(); ++itc)
+      EventCallbackList* el = k->second;
+      if (el)
         {
-        m_current_started = monotonictime;
-        m_current_callback = *itc;
-        m_current_callback->m_callback(m_current_event, msg->body.signal.data);
-        m_current_callback = NULL;
+        for (EventCallbackList::iterator itc=el->begin(); itc!=el->end(); ++itc)
+          {
+          m_current_started = monotonictime;
+          m_current_callback = *itc;
+          if (m_current_callback->m_callback)
+            {
+            m_current_callback->m_callback(m_current_event, msg->body.signal.data);
+            }
+          m_current_callback = NULL;
+          }
         }
       }
     }
 
+  // Run scripts:
   m_current_started = monotonictime;
   MyScripts.EventScript(m_current_event, msg->body.signal.data);
 
@@ -344,8 +367,33 @@ void OvmsEvents::FreeQueueSignalEvent(event_queue_t* msg)
   free(msg->body.signal.event);
   }
 
+
 void OvmsEvents::RegisterEvent(std::string caller, std::string event, EventCallback callback)
   {
+  // To guarantee a newly registered handler will never be called for the current event
+  // if registered from within an event callback, adding the handler is always delegated
+  // to the EventTask:
+
+  event_queue_t msg = {};
+  msg.type = EVENT_addhandler;
+  msg.body.addhandler.event = strdup(event.c_str());
+  msg.body.addhandler.handler = new EventCallbackEntry(caller, callback);
+
+  if (xQueueSend(m_taskqueue, &msg, 0) != pdTRUE)
+    {
+    CheckQueueOverflow("RegisterEvent", msg.body.addhandler.event);
+    free(msg.body.addhandler.event);
+    delete msg.body.addhandler.handler;
+    }
+  }
+
+void OvmsEvents::HandleQueueAddHandler(event_queue_t* msg)
+  {
+  // EventTask command EVENT_addhandler
+  std::string event = msg->body.addhandler.event;
+
+  OvmsRecMutexLock lock(&m_map_mutex);
+
   auto k = m_map.find(event);
   if (k == m_map.end())
     {
@@ -354,16 +402,66 @@ void OvmsEvents::RegisterEvent(std::string caller, std::string event, EventCallb
     }
   if (k == m_map.end())
     {
-    ESP_LOGE(TAG, "Problem registering event %s for caller %s",event.c_str(),caller.c_str());
-    return;
+    ESP_LOGE(TAG, "Problem registering event %s for caller %s", event.c_str(),
+      msg->body.addhandler.handler->m_caller.c_str());
+    free(msg->body.addhandler.event);
+    delete msg->body.addhandler.handler;
+    }
+  else
+    {
+    EventCallbackList *el = k->second;
+    el->push_back(msg->body.addhandler.handler);
+    free(msg->body.addhandler.event);
     }
-
-  EventCallbackList *el = k->second;
-  el->push_back(new EventCallbackEntry(caller,callback));
   }
 
+
 void OvmsEvents::DeregisterEvent(std::string caller)
   {
+  // We need to invalidate all registered handlers in a first pass, to allow this
+  // being called from within a callback (ie within HandleQueueSignalEvent).
+  // Actual deletion of the handlers is then delegated to the EventTask.
+
+  // Invalidate callbacks:
+    {
+    OvmsRecMutexLock lock(&m_map_mutex);
+    EventMap::iterator itm=m_map.begin();
+    while (itm!=m_map.end())
+      {
+      EventCallbackList* el = itm->second;
+      EventCallbackList::iterator itc=el->begin();
+      while (itc!=el->end())
+        {
+        EventCallbackEntry* ec = *itc;
+        if (ec->m_caller == caller)
+          {
+          ec->m_callback = nullptr;
+          }
+        ++itc;
+        }
+      ++itm;
+      }
+    }
+
+  // Schedule deletion:
+  event_queue_t msg = {};
+  msg.type = EVENT_removehandlers;
+  msg.body.removehandlers.caller = strdup(caller.c_str());
+
+  if (xQueueSend(m_taskqueue, &msg, 0) != pdTRUE)
+    {
+    CheckQueueOverflow("DeregisterEvent", msg.body.removehandlers.caller);
+    free(msg.body.removehandlers.caller);
+    }
+  }
+
+void OvmsEvents::HandleQueueRemoveHandlers(event_queue_t* msg)
+  {
+  // EventTask command EVENT_removehandlers
+  std::string caller = msg->body.removehandlers.caller;
+
+  OvmsRecMutexLock lock(&m_map_mutex);
+
   EventMap::iterator itm=m_map.begin();
   while (itm!=m_map.end())
     {
@@ -392,6 +490,8 @@ void OvmsEvents::DeregisterEvent(std::string caller)
       ++itm;
       }
     }
+  
+  free(msg->body.removehandlers.caller);
   }
 
 static void CheckQueueOverflow(const char* from, char* event)
diff --git a/vehicle/OVMS.V3/main/ovms_events.h b/vehicle/OVMS.V3/main/ovms_events.h
index f1120a28..22a6a538 100644
--- a/vehicle/OVMS.V3/main/ovms_events.h
+++ b/vehicle/OVMS.V3/main/ovms_events.h
@@ -76,6 +76,8 @@ extern void EventStdFree(const char* event, void* data);
 typedef enum
   {
   EVENT_none = 0,             // Do nothing
+  EVENT_addhandler,           // Add an event handler
+  EVENT_removehandlers,       // Remove event handlers
   EVENT_signal                // Raise a signal
   } event_msg_t;
 
@@ -83,6 +85,15 @@ typedef struct
   {
   union
     {
+    struct
+      {
+      char* event;
+      EventCallbackEntry* handler;
+      } addhandler;
+    struct
+      {
+      char* caller;
+      } removehandlers;
     struct
       {
       char* event;
@@ -110,7 +121,6 @@ class OvmsEvents
 
   public:
     void EventTask();
-    void HandleQueueSignalEvent(event_queue_t* msg);
     void FreeQueueSignalEvent(event_queue_t* msg);
 #if ESP_IDF_VERSION_MAJOR >= 4
     static void ReceiveSystemEvent(void* handler_args, esp_event_base_t base, int32_t id, void* event_data);
@@ -120,12 +130,18 @@ class OvmsEvents
 #endif
     const EventMap& Map() { return m_map; }
 
+  protected:
+    void HandleQueueSignalEvent(event_queue_t* msg);
+    void HandleQueueAddHandler(event_queue_t* msg);
+    void HandleQueueRemoveHandlers(event_queue_t* msg);
+
   protected:
     bool ScheduleEvent(event_queue_t* msg, uint32_t delay_ms);
     static void SignalScheduledEvent(TimerHandle_t timer);
 
   protected:
     EventMap m_map;
+    OvmsRecMutex m_map_mutex;
     TimerList m_timers;
     TimerStatusMap m_timer_active;
     OvmsMutex m_timers_mutex;
diff --git a/vehicle/OVMS.V3/support/sdkconfig.default.hw31 b/vehicle/OVMS.V3/support/sdkconfig.default.hw31
index 3a8201e9..054c2df5 100644
--- a/vehicle/OVMS.V3/support/sdkconfig.default.hw31
+++ b/vehicle/OVMS.V3/support/sdkconfig.default.hw31
@@ -617,7 +617,7 @@ CONFIG_OVMS_HW_BASE_3_1=y
 CONFIG_OVMS_HW_SPIMEM_AGGRESSIVE=y
 CONFIG_OVMS_HW_CONSOLE_QUEUE_SIZE=100
 CONFIG_OVMS_HW_ASYNC_QUEUE_SIZE=100
-CONFIG_OVMS_HW_EVENT_QUEUE_SIZE=40
+CONFIG_OVMS_HW_EVENT_QUEUE_SIZE=100
 CONFIG_OVMS_HW_NETMANAGER_QUEUE_SIZE=10
 CONFIG_OVMS_HW_CAN_RX_QUEUE_SIZE=60
 CONFIG_OVMS_HW_CAN_TX_QUEUE_SIZE=30
