Station API

Station API is used to work with ESP acting in station mode. It allows to join other access point, scan for available access points or simply disconnect from it.

An example below is showing how all examples (coming with this library) scan for access point and then try to connect to AP from list of preferred one.

Station manager used with all examples
  1/*
  2 * Station manager to connect station to access point.
  3 *
  4 * It is consider as a utility module, simple set of helper functions
  5 * to quickly connect to access point.
  6 * 
  7 * It utilizes 2 different modes, sequential or asynchronous.
  8 * 
  9 * Sequential:
 10 * ==========
 11 * Call station_manager_connect_to_preferred_access_point function to connect to access point
 12 * in blocking mode until being ready to move forward.
 13 * 
 14 * Asynchronous:
 15 * ============
 16 * Call station_manager_connect_to_access_point_async_init to initialize
 17 * asynchronous connect mode and activity will react upon received LwESP events to application.
 18 * 
 19 * Define list of access points:
 20 * ============================
 21 * Have a look at "ap_list_preferred" variable and define
 22 * list of preferred access point's SSID and password.
 23 * Ordered by "most preferred" at the lower array index.
 24 */
 25#include "station_manager.h"
 26#include "lwesp/lwesp.h"
 27#include "utils.h"
 28
 29/**
 30 * \brief           Private access-point and station management system
 31 * 
 32 * This is used for asynchronous connection to access point
 33 */
 34typedef struct {
 35    size_t index_preferred_list; /*!< Current index position of preferred array */
 36    size_t index_scanned_list;   /*!< Current index position in array of scanned APs */
 37
 38    uint8_t command_is_running; /*!< Indicating if command is currently in progress */
 39} prv_ap_data_t;
 40
 41/* Arguments for callback function */
 42#define ARG_SCAN    (void*)1
 43#define ARG_CONNECT (void*)2
 44
 45/* Function declaration */
 46static void prv_cmd_event_fn(lwespr_t status, void* arg);
 47static void prv_try_next_access_point(void);
 48
 49/*
 50 * List of preferred access points for ESP device
 51 * SSID and password
 52 *
 53 * ESP will try to scan for access points
 54 * and then compare them with the one on the list below
 55 */
 56static const ap_entry_t ap_list_preferred[] = {
 57    //{ .ssid = "SSID name", .pass = "SSID password" },
 58    {.ssid = "TilenM_ST", .pass = "its private"},
 59    {.ssid = "404WiFiNotFound", .pass = "its private"},
 60    {.ssid = "Majerle WIFI", .pass = "majerle_internet_private"},
 61    {.ssid = "Majerle AMIS", .pass = "majerle_internet_private"},
 62};
 63static lwesp_ap_t ap_list_scanned[100]; /* Scanned access points information */
 64static size_t ap_list_scanned_len = 0;  /* Number of scanned access points */
 65static prv_ap_data_t ap_async_data;     /* Asynchronous data structure */
 66
 67/* Command to execute to start scanning access points */
 68#define prv_scan_ap_command_ex(blocking)                                                                               \
 69    lwesp_sta_list_ap(NULL, ap_list_scanned, LWESP_ARRAYSIZE(ap_list_scanned), &ap_list_scanned_len, NULL, NULL,       \
 70                      (blocking))
 71#define prv_scan_ap_command()                                                                                          \
 72    do {                                                                                                               \
 73        if (!ap_async_data.command_is_running) {                                                                       \
 74            ap_async_data.command_is_running =                                                                         \
 75                lwesp_sta_list_ap(NULL, ap_list_scanned, LWESP_ARRAYSIZE(ap_list_scanned), &ap_list_scanned_len,       \
 76                                  prv_cmd_event_fn, ARG_SCAN, 0)                                                       \
 77                == lwespOK;                                                                                            \
 78        }                                                                                                              \
 79    } while (0)
 80
 81/**
 82 * \brief           Every internal command execution callback
 83 * \param[in]       status: Execution status result
 84 * \param[in]       arg: Custom user argument
 85 */
 86static void
 87prv_cmd_event_fn(lwespr_t status, void* arg) {
 88    LWESP_UNUSED(status);
 89    /*
 90     * Command has now successfully finish
 91     * and callbacks have been properly processed
 92     */
 93    ap_async_data.command_is_running = 0;
 94
 95    if (arg == ARG_SCAN) {
 96        /* Immediately try to connect to access point after successful scan */
 97        prv_try_next_access_point();
 98    }
 99}
100
101/**
102 * \brief           Try to connect to next access point on a list 
103 */
104static void
105prv_try_next_access_point(void) {
106    uint8_t tried = 0;
107
108    /* No action to be done if command is currently in progress or already connected to network */
109    if (ap_async_data.command_is_running || lwesp_sta_has_ip()) {
110        return;
111    }
112
113    /*
114     * Process complete list and try to find suitable match
115     *
116     * Use global variable for indexes to be able to call function multiple times
117     * and continue where it finished previously
118     */
119
120    /* List all preferred access points */
121    for (; ap_async_data.index_preferred_list < LWESP_ARRAYSIZE(ap_list_preferred);
122         ap_async_data.index_preferred_list++, ap_async_data.index_scanned_list = 0) {
123
124        /* List all scanned access points */
125        for (; ap_async_data.index_scanned_list < ap_list_scanned_len; ap_async_data.index_scanned_list++) {
126
127            /* Find a match if available */
128            if (strncmp(ap_list_scanned[ap_async_data.index_scanned_list].ssid,
129                        ap_list_preferred[ap_async_data.index_preferred_list].ssid,
130                        strlen(ap_list_preferred[ap_async_data.index_preferred_list].ssid))
131                == 0) {
132
133                /* Try to connect to the network */
134                if (!ap_async_data.command_is_running
135                    && lwesp_sta_join(ap_list_preferred[ap_async_data.index_preferred_list].ssid,
136                                      ap_list_preferred[ap_async_data.index_preferred_list].pass, NULL,
137                                      prv_cmd_event_fn, ARG_CONNECT, 0)
138                           == lwespOK) {
139                    ap_async_data.command_is_running = 1;
140
141                    /* Go to next index for sub-for loop and exit */
142                    ap_async_data.index_scanned_list++;
143                    tried = 1;
144                    goto stp;
145                } else {
146                    /* We have a problem, needs to resume action in next run */
147                }
148            }
149        }
150    }
151
152    /* Restart scan operation if there was no try to connect and station has no IP */
153    if (!tried && !lwesp_sta_has_ip()) {
154        prv_scan_ap_command();
155    }
156stp:
157    return;
158}
159
160/**
161 * \brief           Private event function for asynchronous scanning
162 * \param[in]       evt: Event information
163 * \return          \ref lwespOK on success, member of \ref lwespr_t otherwise
164 */
165static lwespr_t
166prv_evt_fn(lwesp_evt_t* evt) {
167    switch (evt->type) {
168        case LWESP_EVT_KEEP_ALIVE:
169        case LWESP_EVT_WIFI_DISCONNECTED: {
170            /* Try to connect to next access point */
171            prv_try_next_access_point();
172            break;
173        }
174        case LWESP_EVT_STA_LIST_AP: {
175            /*
176             * After scanning gets completed
177             * manually reset all indexes for comparison purposes
178             */
179            ap_async_data.index_scanned_list = 0;
180            ap_async_data.index_preferred_list = 0;
181
182            /* Actual connection try is done in function callback */
183            break;
184        }
185        default: break;
186    }
187    return lwespOK;
188}
189
190/**
191 * \brief           Initialize asynchronous mode to connect to preferred access point
192 *
193 * Asynchronous mode relies on system events received by the application,
194 * to determine current device status if station is being, or not, connected to access point.
195 *
196 * When used, async acts only upon station connection change through callbacks,
197 * therefore it does not require additional system thread or user code,
198 * to be able to properly handle preferred access points.
199 * This certainly decreases memory consumption of the complete system.
200 *
201 * \ref LWESP_CFG_KEEP_ALIVE feature must be enable to properly handle all events
202 * \return          \ref lwespOK on success, member of \ref lwespr_t otherwise
203 */
204lwespr_t
205station_manager_connect_to_access_point_async_init(void) {
206    /* Register system event function */
207    lwesp_evt_register(prv_evt_fn);
208
209    /*
210     * Start scanning process in non-blocking mode
211     *
212     * This is the only command being executed from non-callback mode,
213     * therefore it must be protected against other threads trying to access the same core
214     */
215    lwesp_core_lock();
216    prv_scan_ap_command();
217    lwesp_core_unlock();
218
219    /* Return all good, things will progress (from now-on) asynchronously */
220    return lwespOK;
221}
222
223/**
224 * \brief           Connect to preferred access point in blocking mode
225 * 
226 * This functionality can only be used if non-blocking approach is not used
227 * 
228 * \note            List of access points should be set by user in \ref ap_list structure
229 * \param[in]       unlimited: When set to 1, function will block until SSID is found and connected
230 * \return          \ref lwespOK on success, member of \ref lwespr_t enumeration otherwise
231 */
232lwespr_t
233station_manager_connect_to_preferred_access_point(uint8_t unlimited) {
234    lwespr_t eres;
235    uint8_t tried;
236
237    /*
238     * Scan for network access points
239     * In case we have access point,
240     * try to connect to known AP
241     */
242    do {
243        if (lwesp_sta_has_ip()) {
244            return lwespOK;
245        }
246
247        /* Scan for access points visible to ESP device */
248        printf("Scanning access points...\r\n");
249        if ((eres = prv_scan_ap_command_ex(1)) == lwespOK) {
250            tried = 0;
251
252            /* Print all access points found by ESP */
253            for (size_t i = 0; i < ap_list_scanned_len; i++) {
254                printf("AP found: %s, CH: %d, RSSI: %d\r\n", ap_list_scanned[i].ssid, ap_list_scanned[i].ch,
255                       ap_list_scanned[i].rssi);
256            }
257
258            /* Process array of preferred access points with array of found points */
259            for (size_t j = 0; j < LWESP_ARRAYSIZE(ap_list_preferred); j++) {
260
261                /* Go through all scanned list */
262                for (size_t i = 0; i < ap_list_scanned_len; i++) {
263
264                    /* Try to find a match between preferred and scanned */
265                    if (strncmp(ap_list_scanned[i].ssid, ap_list_preferred[j].ssid, strlen(ap_list_scanned[i].ssid))
266                        == 0) {
267                        tried = 1;
268                        printf("Connecting to \"%s\" network...\r\n", ap_list_preferred[j].ssid);
269
270                        /* Try to join to access point */
271                        if ((eres = lwesp_sta_join(ap_list_preferred[j].ssid, ap_list_preferred[j].pass, NULL, NULL,
272                                                   NULL, 1))
273                            == lwespOK) {
274                            lwesp_ip_t ip;
275                            uint8_t is_dhcp;
276
277                            printf("Connected to %s network!\r\n", ap_list_preferred[j].ssid);
278
279                            lwesp_sta_copy_ip(&ip, NULL, NULL, &is_dhcp);
280                            utils_print_ip("Station IP address: ", &ip, "\r\n");
281                            printf("; Is DHCP: %d\r\n", (int)is_dhcp);
282                            return lwespOK;
283                        } else {
284                            printf("Connection error: %d\r\n", (int)eres);
285                        }
286                    }
287                }
288            }
289            if (!tried) {
290                printf("No access points available with preferred SSID!\r\nPlease check station_manager.c file and "
291                       "edit preferred SSID access points!\r\n");
292            }
293        } else if (eres == lwespERRNODEVICE) {
294            printf("Device is not present!\r\n");
295            break;
296        } else {
297            printf("Error on WIFI scan procedure!\r\n");
298        }
299        if (!unlimited) {
300            break;
301        }
302    } while (1);
303    return lwespERR;
304}
group LWESP_STA

Station API.

Functions

lwespr_t lwesp_sta_join(const char *name, const char *pass, const lwesp_mac_t *mac, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Join as station to access point.

Configuration changes will be saved in the NVS area of ESP device.

Parameters
  • name[in] SSID of access point to connect to

  • pass[in] Password of access point. Use NULL if AP does not have password

  • mac[in] Pointer to MAC address of AP. If multiple APs with same name exist, MAC may help to select proper one. Set to NULL if not needed

  • evt_fn[in] Callback function called when command has finished. Set to NULL when not used

  • evt_arg[in] Custom argument for event callback function

  • blocking[in] Status whether command should be blocking or not

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_quit(const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Quit (disconnect) from access point.

Parameters
  • evt_fn[in] Callback function called when command has finished. Set to NULL when not used

  • evt_arg[in] Custom argument for event callback function

  • blocking[in] Status whether command should be blocking or not

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_autojoin(uint8_t en, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Configure auto join to access point on startup.

Note

For auto join feature, you need to do a join to access point with default mode. Check lwesp_sta_join for more information

Parameters
  • en[in] Set to 1 to enable or 0 to disable

  • evt_fn[in] Callback function called when command has finished. Set to NULL when not used

  • evt_arg[in] Custom argument for event callback function

  • blocking[in] Status whether command should be blocking or not

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_reconnect_set_config(uint16_t interval, uint16_t rep_cnt, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Set reconnect interval and maximum tries when connection drops.

Parameters
  • interval[in] Interval in units of seconds. Valid numbers are 1-7200 or 0 to disable reconnect feature

  • rep_cnt[in] Repeat counter. Number of maximum tries for reconnect. Valid entries are 1-1000 or 0 to always try. This parameter is only valid if interval is not 0

  • evt_fn[in] Callback function called when command has finished. Set to NULL when not used

  • evt_arg[in] Custom argument for event callback function

  • blocking[in] Status whether command should be blocking or not

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_getip(lwesp_ip_t *ip, lwesp_ip_t *gw, lwesp_ip_t *nm, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get station IP address.

Parameters
  • ip[out] Pointer to variable to save IP address

  • gw[out] Pointer to output variable to save gateway address

  • nm[out] Pointer to output variable to save netmask address

  • evt_fn[in] Callback function called when command has finished. Set to NULL when not used

  • evt_arg[in] Custom argument for event callback function

  • blocking[in] Status whether command should be blocking or not

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_setip(const lwesp_ip_t *ip, const lwesp_ip_t *gw, const lwesp_ip_t *nm, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Set station IP address.

Application may manually set IP address. When this happens, stack will check for DHCP settings and will read actual IP address from device. Once procedure is finished, LWESP_EVT_WIFI_IP_ACQUIRED event will be sent to application where user may read the actual new IP and DHCP settings.

Configuration changes will be saved in the NVS area of ESP device.

Note

DHCP is automatically disabled when using static IP address

Parameters
  • ip[in] Pointer to IP address

  • gw[in] Pointer to gateway address. Set to NULL to use default gateway

  • nm[in] Pointer to netmask address. Set to NULL to use default netmask

  • evt_fn[in] Callback function called when command has finished. Set to NULL when not used

  • evt_arg[in] Custom argument for event callback function

  • blocking[in] Status whether command should be blocking or not

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_getmac(lwesp_mac_t *mac, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get station MAC address.

Parameters
  • mac[out] Pointer to output variable to save MAC address

  • evt_fn[in] Callback function called when command has finished. Set to NULL when not used

  • evt_arg[in] Custom argument for event callback function

  • blocking[in] Status whether command should be blocking or not

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_setmac(const lwesp_mac_t *mac, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Set station MAC address.

Configuration changes will be saved in the NVS area of ESP device.

Parameters
  • mac[in] Pointer to variable with MAC address

  • evt_fn[in] Callback function called when command has finished. Set to NULL when not used

  • evt_arg[in] Custom argument for event callback function

  • blocking[in] Status whether command should be blocking or not

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

uint8_t lwesp_sta_has_ip(void)

Check if ESP got IP from access point.

Returns

1 on success, 0 otherwise

uint8_t lwesp_sta_is_joined(void)

Check if station is connected to WiFi network.

Returns

1 on success, 0 otherwise

lwespr_t lwesp_sta_copy_ip(lwesp_ip_t *ip, lwesp_ip_t *gw, lwesp_ip_t *nm, uint8_t *is_dhcp)

Copy IP address from internal value to user variable.

Note

Use lwesp_sta_getip to refresh actual IP value from device

Parameters
  • ip[out] Pointer to output IP variable. Set to NULL if not interested in IP address

  • gw[out] Pointer to output gateway variable. Set to NULL if not interested in gateway address

  • nm[out] Pointer to output netmask variable. Set to NULL if not interested in netmask address

  • is_dhcp[out] Pointer to output DHCP status variable. Set to NULL if not interested

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_list_ap(const char *ssid, lwesp_ap_t *aps, size_t apsl, size_t *apf, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

List for available access points ESP can connect to.

Parameters
  • ssid[in] Optional SSID name to search for. Set to NULL to disable filter

  • aps[in] Pointer to array of available access point parameters

  • apsl[in] Length of aps array

  • apf[out] Pointer to output variable to save number of access points found

  • evt_fn[in] Callback function called when command has finished. Set to NULL when not used

  • evt_arg[in] Custom argument for event callback function

  • blocking[in] Status whether command should be blocking or not

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_get_ap_info(lwesp_sta_info_ap_t *info, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get current access point information (name, mac, channel, rssi)

Note

Access point station is currently connected to

Parameters
  • info[in] Pointer to connected access point information

  • evt_fn[in] Callback function called when command has finished. Set to NULL when not used

  • evt_arg[in] Custom argument for event callback function

  • blocking[in] Status whether command should be blocking or not

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

uint8_t lwesp_sta_is_ap_802_11b(lwesp_ap_t *ap)

Check if access point is 802.11b compatible.

Parameters

ap[in] Access point detailes acquired by lwesp_sta_list_ap

Returns

1 on success, 0 otherwise

uint8_t lwesp_sta_is_ap_802_11g(lwesp_ap_t *ap)

Check if access point is 802.11g compatible.

Parameters

ap[in] Access point detailes acquired by lwesp_sta_list_ap

Returns

1 on success, 0 otherwise

uint8_t lwesp_sta_is_ap_802_11n(lwesp_ap_t *ap)

Check if access point is 802.11n compatible.

Parameters

ap[in] Access point detailes acquired by lwesp_sta_list_ap

Returns

1 on success, 0 otherwise

uint8_t lwesp_sta_has_ipv6_local(void)

Check if station has local IPV6 IP Local IP is used between station and router.

Note

Defined as macro with 0 constant if LWESP_CFG_IPV6 is disabled

Returns

1 if local IPv6 is available, 0 otherwise

uint8_t lwesp_sta_has_ipv6_global(void)

Check if station has global IPV6 IP Global IP is used router and outside network.

Note

Defined as macro with 0 constant if LWESP_CFG_IPV6 is disabled

Returns

1 if global IPv6 is available, 0 otherwise

struct lwesp_sta_t
#include <lwesp_types.h>

Station data structure.

Public Members

lwesp_ip_t ip

IP address of connected station

lwesp_mac_t mac

MAC address of connected station