Wifi Task

The wifi task manages connecting and reconnecting to a wifi network, setting the mdns hostname and ip address of the device, and searching for the mqtt broker.

Configuration

WIFI_VERBOSE_LOGGING

if set to 1, the wifi task will log any wifi events to the console.

#define WIFI_VERBOSE_LOGGING 0

EXPONENTIAL_BACKOFF_START

the initial time to wait before reconnecting to a wifi network after a failure in ms.

#define EXPONENTIAL_BACKOFF_START (100)

EXPONENTIAL_BACKOFF_MAX

the maximum time to wait before reconnecting to a wifi network after a failure in ms.

#define EXPONENTIAL_BACKOFF_MAX (30000)

Public Variables

current_ip

the current ip address of the device as a string in format A.B.C.D . is empty string "" if not connected to a wifi network.

char current_ip[20] = {0};

server_ip

the ip address of the broker as a string in format A.B.C.D . is empty string "" if not found.

char server_ip[20] = {0};

hostname

the mdns hostname of the device as a string. in the form ReGen_XXXXXXXXXXXX where X is a hex digit.

char hostname[32] = {0};

Public Functions

find_broker

triggers a rescan for the mqtt broker, can block for up to 1 second.

void find_broker(void)
{
    esp_ip4_addr_t ip;
    esp_err_t res = mdns_query_a("egym_broker", 1000, &ip);
    if (res == ESP_OK)
    {
        sprintf(server_ip, IPSTR, IP2STR(&ip));
        WIFI_LOG_VERBOSE("found mqtt broker at %s\n", server_ip);
    }
    else
    {
        WIFI_LOG_VERBOSE("failed to find mqtt broker on local network\n");
    }
}

wifi_is_connected

returns true if the device is currently connected to a wifi network.

bool wifi_is_connected(void)
{
    return xEventGroupGetBits(s_wifi_event_group) & WIFI_CONNECTED_BIT;
}

wifi_init()

initializes the wifi task.

void wifi_init(void)
{
    wifi_cient_init();
    mdns_start();
    // wifi_logging_init();
}

Private Variables

s_wifi_event_group

the event group for the wifi task. used for wifi_is_connected().

static EventGroupHandle_t s_wifi_event_group;

exponential_backoff

the current time to wait before reconnecting to a wifi network after a failure in ms doubles each failiure, until it reaches its maximum.

static int exponential_backoff = EXPONENTIAL_BACKOFF_START;

Private Functions

event_handler

handles wifi events from the ESP WiFi stack. tries to reconnect to the wifi network if disconnected. sets the current ip address if connected.

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)
    {
        memset(current_ip, 0, sizeof(current_ip));
        xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);

        if (exponential_backoff < EXPONENTIAL_BACKOFF_MAX)
        {
            exponential_backoff *= 2;
        }
        WIFI_LOG_VERBOSE("failed to connect to the AP, wait %dms", exponential_backoff);
        vTaskDelay(pdMS_TO_TICKS(exponential_backoff));
        esp_wifi_connect();
        WIFI_LOG_VERBOSE("retry to connect to the AP");
    }
    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;
        memset(current_ip, 0, sizeof(current_ip));
        sprintf(current_ip, IPSTR, IP2STR(&event->ip_info.ip));
        exponential_backoff = EXPONENTIAL_BACKOFF_START;
        WIFI_LOG_VERBOSE("got ip: %s", current_ip);
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}

wifi_cient_init

initializes the ESP WiFi stack.

static esp_err_t wifi_cient_init(void)
{
    esp_err_t res = ESP_OK;
    s_wifi_event_group = xEventGroupCreate();
    res |= esp_netif_init();
    res |= esp_event_loop_create_default();
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    res |= esp_wifi_init(&cfg);

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    res |= esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id);
    res |= esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip);

    wifi_config_t wifi_config = {
        .sta =
            {
                .ssid = "Energym_bikes",
                .password = "[REDACTED]",
                .threshold.authmode = WIFI_AUTH_OPEN,
                .sae_pwe_h2e = WPA3_SAE_PWE_UNSPECIFIED,
            },
    };

    res |= esp_wifi_set_mode(WIFI_MODE_STA);
    res |= esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
    res |= esp_wifi_start();

    return res;
}

mdns_start

starts the mdns service. registers the mdns hostname of the device. registers a .egym.tcp service for the device so zeroconf clients can find it.

static void mdns_start()
{
    mdns_init();
    uint8_t mac[8];
    esp_read_mac(mac, ESP_MAC_BT);
    sprintf(hostname, "ReGen_%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    mdns_hostname_set(hostname);
    mdns_instance_name_set(hostname);
    mdns_service_add(NULL, "_egym", "_tcp", 80, NULL, 0);
}