espressif / esp-apple-homekit-adk

This is a port for Apple's Open Source HomeKit ADK
617 stars 64 forks source link

Stops working after a while #18

Open g-mocken opened 3 years ago

g-mocken commented 3 years ago

I frequently see the homekit device becoming unresponsive. I managed to capture the precise moment in the terminal:

1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Core:IPAccessoryServer] session:0x3ffb9d20:input closed 1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Core:IPAccessoryServer] session:0x3ffb9d20:closing 1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Core:IPAccessoryServer] session:0x3ffb9d20:closing security context 1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Core:IPAccessoryServer] Closing HAP session. 1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Core:Session] HAPSessionRelease 1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Core:Session] HAPSessionInvalidate 1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Core:IPAccessoryServer] session:0x3ffb9d20:closing TCP stream 1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Platform:TCPStreamManager] shutdown(51, SHUT_RDWR); 1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Platform:TCPStreamManager] close(51); 1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Core:IPAccessoryServer] session:0x3ffb9d20:closed 1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Core:IPAccessoryServer] session:0x3ffb9d20:releasing session 1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Core:IPAccessoryServer] session:0x3ffba078:input closed 1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Core:IPAccessoryServer] session:0x3ffba078:closing 1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Core:IPAccessoryServer] session:0x3ffba078:closing security context 1970-01-01'T'01:28:47'Z' Debug [com.apple.mfi.HomeKit.Core:IPAccessoryServer] Closing HAP session.

What is happening? Sometimes, it comes back to live on its own later, but not always.

jtbarrett commented 3 years ago

I had the same issue, in app_wifi.c's event_handler you have to handle the disconnected event by calling esp_wifi_connect() again. Here's a version that works for me:

static void event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        ESP_LOGI(TAG, "Reconnecting");
        esp_wifi_connect();
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
    }
}
skanico commented 3 years ago

Hello, I also have this problem (unresponsive after a day or two). It seems we don't have the same app_wifi.c file... Here is my event_handler function :

static void event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
            esp_wifi_connect();
            s_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP");
        } else {
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
        }
        ESP_LOGI(TAG,"connect to the AP fail");
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        s_retry_num = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}

I just updated EXAMPLE_ESP_MAXIMUM_RETRY from 5 to 10, but I'm not sure this will help.

izmmisha commented 3 years ago

but I'm not sure this will help.

In the original example event handler removed after connection established:

esp_err_t app_wifi_connect(void)
{

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
[...]
    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
    vEventGroupDelete(s_wifi_event_group);
    return err;
}

event handler with esp_wifi_connect() should exists all the time.

skanico commented 3 years ago

Thanks @izmmisha I modified this function. Let's cross fingers. I give some feedback in a few days

jtbarrett commented 3 years ago

@izmmisha , that version retries the initial connection but doesn’t handle disconnects that happen later. If WiFi drops later you have to call esp_wifi_connect again. For me it would drop after ~24 hours and then never reconnect. You can repro by rebooting your router. With the version I shared it has reliably run my garage door opener for a couple months now.

You can read more about the WiFi events in the esp docs, https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wifi-event-sta-disconnected

Edit: sorry, I’m responding from my phone in the middle of the night and missed that there are two commenters here. I think we’re saying the same thing.

shahpiyushv commented 3 years ago

The code in app_wifi.c was taken from the esp idf Wi-Fi station example. Ofcourse, the logic of trying just 5 times at the beginning and also unsubscribing from the events on a successful connection made no sense here. I have changed that behaviour now.

skanico commented 3 years ago

Thanks @shahpiyushv ! Shouldn't this code be moved to app_wifi_init?

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));
Yurik72 commented 3 years ago

I have a similar issue in my library https://github.com/Yurik72/ESPHap/issues/34 The problem is that power mode on esp32 is WIFI_PS_MIN_MODEM by default (maybe i'm wrong), which means that radio wake up every DTIM (100 ms) to check for packets . But for communication with Apple mDNS is neccessary. mDNS is UDP, which is not able to track sent/receiving data and some UPD packets are lost.Therefore solution is

esp_wifi_set_ps(WIFI_PS_NONE);

I my case after that changes device work well with the Apple

g-mocken commented 3 years ago

Thanks, using "WIFI_PS_NONE" definitely helps to some extent - I have to monitor it for longer times to see if the issue is resolved completely.

angryDuck2 commented 3 years ago

Hello as I am having the same issue as @g-mocken I would like to ask for some advice. I am currently utilising the dual stack capabilities for esp32. Meaning I use wifi+ble for a project of mine. According to Espressif documentation setting WIFI_PS_NONE is impossible when using the dual stack environment. Is there anything else that can be done to correct this issue?