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

Station data structure.

Public Members

lwesp_ip_t ip

IP address of connected station

lwesp_mac_t mac

MAC address of connected station