259 == ESP_ERR_INVALID_STATE according to this. Your error likely came from here:
esp_err_t esp_event_handler_instance_unregister(esp_event_base_t event_base,
int32_t event_id,
esp_event_handler_instance_t context)
{
if (s_default_loop == NULL) {
return ESP_ERR_INVALID_STATE;
}
...
You're perhaps calling the function too early, before a default event loop even exists. I'm guessing that usually this event loop gets created by the WiFi libs when you start WiFi-related calls -- such as here:
static bool _start_network_event_task(){
...
esp_err_t err = esp_event_loop_create_default();
If you try moving your registration to after the softAP() call, you risk missing events, depending on how synchronous that call is. So you can try creating the event loop yourself explicitly:
// Create the default event loop
ESP_ERROR_CHECK(esp_event_loop_create_default());
...before you register the handler. That should be harmless -- anything else that tries to create this same loop later should cleanly handle the returned error that indicates the loop already exists.
EDIT
So I tried out your sketch and met the same issue. After spending more time than should've been needed, the issue boils down to one of compatibility.
My ESP32-Arduino core 1.0.6 (and likely yours as well) is based on the ESP-IDF/SDK 3.3.5 release -- a release that contains some pretty old code, despite being the latest that the Arduino Boards Manager has to offer. So, esp_event_loop_init() looked like this:
esp_err_t esp_event_loop_init(system_event_cb_t cb, void *ctx)
{
if (s_event_init_flag) {
return ESP_FAIL;
}
s_event_handler_cb = cb;
s_event_ctx = ctx;
s_event_queue = xQueueCreate(CONFIG_SYSTEM_EVENT_QUEUE_SIZE, sizeof(system_event_t));
xTaskCreatePinnedToCore(esp_event_loop_task, "eventTask",
ESP_TASKD_EVENT_STACK, NULL, ESP_TASKD_EVENT_PRIO, NULL, 0);
s_event_init_flag = true;
return ESP_OK;
}
and WiFiGeneric.cpp looked like this:
static bool _start_network_event_task(){
...
return esp_event_loop_init(&_network_event_cb, NULL) == ESP_OK;
As you can see, there's no mention of the default loop being created, which is why you get *INVALID_STATE for any registrations.
Even if you went and created the default loop yourself, you'd receive no events in your handler because the system events, as of this IDF version, aren't passing through the official esp_event loop pipeline -- esp_event_loop_init() just creates a Task and this task receives events from some external caller as they happen, forwarding them to one application task alone.
If you still want to receive events through this way, you'd need to download/install the very latest ESP32 Arduino core from Github, rather than through the Boards Manager. This core should have a more recent version of the SDK, along with a compatible Arduino HAL.
Alternatively, you can just use the more public API, WiFi.onEvent(). It should cover all the events you're interested in, as well as include any relevant reason codes.
EDIT 2
Yeah, it turns out the SYSTEM_EVENT_AP_STADISCONNECTED reason codes you're looking for, just aren't exposed by the Espressif API, at any layer of the stack. Nor is there any other event which would give you this info AFAICT. You can try raising an issue on the ESP-IDF Github page to see if they can help you there, but chances aren't looking great.