Search code examples
ctcpembeddeddriveresp32

How to correctly set the hostname for the TCP/IP adapter on the ESP32


Problem

Espressif's ESP-32 (specifically the ESP-WROOM-32 in this case) appears on a network with the default hostname "Espressif". I don't want to use this hostname, so I've opted to change it as follows:

    // Initialize the TCP/IP adapter (launches handler task)
    tcpip_adapter_init();

    // Set the hostname for the default TCP/IP station interface
    if ((err = tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, g_hostname))
            != ESP_OK) {
        return err;
    }

Of course, this isn't working. I get back the following error: ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY.


Attempted Solutions

To solve this, I look to see if the TCP/IP adapter will post some kind of event when it is finished initializing. That way I can register a handler to set the hostname. The Espressif WiFi Driver Guide here indicates a task is launched - so there is probably an event right:

"The main task calls tcpip_adapter_init() to create an LwIP core task and initialize LwIP-related work."

Well I cannot find any such events. Neither the API documentation nor the actual file itself (tcpip_adapter.h) have it. I checked the header file for events, and none seem to exist solely for the purpose of indicating that the TCP/IP adapter has finished starting:

/** IP event declarations */
typedef enum {
    IP_EVENT_STA_GOT_IP,               /*!< ESP32 station got IP from connected AP */
    IP_EVENT_STA_LOST_IP,              /*!< ESP32 station lost IP and the IP is reset to 0 */
    IP_EVENT_AP_STAIPASSIGNED,         /*!< ESP32 soft-AP assign an IP to a connected station */
    IP_EVENT_GOT_IP6,                  /*!< ESP32 station or ap or ethernet interface v6IP addr is preferred */
    IP_EVENT_ETH_GOT_IP,               /*!< ESP32 ethernet got IP from connected AP */
} ip_event_t;

Possible Lead

I have noticed that in Espressif's WiFi guide they indicate that the event SYSTEM_EVENT_STA_START (which indicates that a station has started), will:

Upon receiving this event, the event task will initialize the LwIP network interface (netif).

If I place the call after a handler receives this event, I no longer get the error:


    // After the event WIFI_EVENT_STA_START
    if (base == WIFI_EVENT && id == WIFI_EVENT_STA_START) {

        // Set the hostname for the default TCP/IP station interface
        if ((err = tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, g_hostname))
                != ESP_OK) {
            fprintf(stderr, "Err: %s", esp_err_to_name(err));
        }
        ...
    }

However, the hostname still hasn't changed. Therefore I find myself a bit stuck. How can I actually change the hostname? I've found little to no results from searching this problem. However, the esp32 is a popular module and I'm sure many other people will find themselves facing the same problem.


Solution

  • Turns out I was doing it correctly. It was my router that had failed to refresh the hostname adequately. For consistency I will restate what I did to solve this problem:


    The Espressif WiFi Guide indicates that the event SYSTEM_EVENT_STA_START is generated once esp_wifi_start() returns successfully.

    The generation of this event also means that the event task will initialize the LwIP network interface (netif). Since we know that the TCP/IP adapter will surely have been initialized at this point, we can invoke the hostname change function. Here is an example of a handler that does that, taken right from their example:

    void wifi_event_handler (void *handler_arg, esp_event_base_t base, int32_t id,
        void *event_data) {
        esp_err_t err;
    
        // If esp_wifi_start() returned ESP_OK and WiFi mode is in station mode
        if (base == WIFI_EVENT && id == WIFI_EVENT_STA_START) {
            const char *name;
    
            // Set the hostname for the default TCP/IP station interface
            if ((err = tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, g_hostname))
                    != ESP_OK) {
                fprintf(stderr, "Err: %s", esp_err_to_name(err));
            } else {
                if ((err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &name)) != ESP_OK) {
                    fprintf(stderr, "Err Get Hostname: %s\n", esp_err_to_name(err));
                } else {
                    printf("Hostname: %s\n", (name == NULL ? "<None>" : name));
                }
            }
            ...
        }
        ...
    }
    

    In this example I get the hostname after setting it, and print it to stdout. You can validate it if you are running the monitor for the ESP32. The hostname set will be the one visible from the router page.