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.
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 "utils.h"
27#include "lwesp/lwesp.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 = "Kaja", .pass = "ginkaja2021" },
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) lwesp_sta_list_ap(NULL, ap_list_scanned, LWESP_ARRAYSIZE(ap_list_scanned), &ap_list_scanned_len, NULL, NULL, (blocking))
69#define prv_scan_ap_command() do {\
70 if (!ap_async_data.command_is_running) { \
71 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; \
72 } \
73} while (0)
74
75/**
76 * \brief Every internal command execution callback
77 * \param[in] status: Execution status result
78 * \param[in] arg: Custom user argument
79 */
80static void
81prv_cmd_event_fn(lwespr_t status, void* arg) {
82 LWESP_UNUSED(status);
83 /*
84 * Command has now successfully finish
85 * and callbacks have been properly processed
86 */
87 ap_async_data.command_is_running = 0;
88
89 if (arg == ARG_SCAN) {
90 /* Immediately try to connect to access point after successful scan */
91 prv_try_next_access_point();
92 }
93}
94
95/**
96 * \brief Try to connect to next access point on a list
97 */
98static void
99prv_try_next_access_point(void) {
100 uint8_t tried = 0;
101
102 /* No action to be done if command is currently in progress or already connected to network */
103 if (ap_async_data.command_is_running
104 || lwesp_sta_has_ip()) {
105 return;
106 }
107
108 /*
109 * Process complete list and try to find suitable match
110 *
111 * Use global variable for indexes to be able to call function multiple times
112 * and continue where it finished previously
113 */
114
115 /* List all preferred access points */
116 for (; ap_async_data.index_preferred_list < LWESP_ARRAYSIZE(ap_list_preferred);
117 ap_async_data.index_preferred_list++, ap_async_data.index_scanned_list = 0) {
118
119 /* List all scanned access points */
120 for (; ap_async_data.index_scanned_list < ap_list_scanned_len; ap_async_data.index_scanned_list++) {
121
122 /* Find a match if available */
123 if (strncmp(ap_list_scanned[ap_async_data.index_scanned_list].ssid,
124 ap_list_preferred[ap_async_data.index_preferred_list].ssid,
125 strlen(ap_list_preferred[ap_async_data.index_preferred_list].ssid)) == 0) {
126
127 /* Try to connect to the network */
128 if (!ap_async_data.command_is_running
129 && lwesp_sta_join(ap_list_preferred[ap_async_data.index_preferred_list].ssid,
130 ap_list_preferred[ap_async_data.index_preferred_list].pass,
131 NULL, prv_cmd_event_fn, ARG_CONNECT, 0) == lwespOK) {
132 ap_async_data.command_is_running = 1;
133
134 /* Go to next index for sub-for loop and exit */
135 ap_async_data.index_scanned_list++;
136 tried = 1;
137 goto stp;
138 } else {
139 /* We have a problem, needs to resume action in next run */
140 }
141 }
142 }
143 }
144
145 /* Restart scan operation if there was no try to connect and station has no IP */
146 if (!tried && !lwesp_sta_has_ip()) {
147 prv_scan_ap_command();
148 }
149stp:
150 return;
151}
152
153/**
154 * \brief Private event function for asynchronous scanning
155 * \param[in] evt: Event information
156 * \return \ref lwespOK on success, member of \ref lwespr_t otherwise
157 */
158static lwespr_t
159prv_evt_fn(lwesp_evt_t* evt) {
160 switch (evt->type) {
161 case LWESP_EVT_KEEP_ALIVE:
162 case LWESP_EVT_WIFI_DISCONNECTED: {
163 /* Try to connect to next access point */
164 prv_try_next_access_point();
165 break;
166 }
167 case LWESP_EVT_STA_LIST_AP: {
168 /*
169 * After scanning gets completed
170 * manually reset all indexes for comparison purposes
171 */
172 ap_async_data.index_scanned_list = 0;
173 ap_async_data.index_preferred_list = 0;
174
175 /* Actual connection try is done in function callback */
176 break;
177 }
178 default: break;
179 }
180 return lwespOK;
181}
182
183/**
184 * \brief Initialize asynchronous mode to connect to preferred access point
185 *
186 * Asynchronous mode relies on system events received by the application,
187 * to determine current device status if station is being, or not, connected to access point.
188 *
189 * When used, async acts only upon station connection change through callbacks,
190 * therefore it does not require additional system thread or user code,
191 * to be able to properly handle preferred access points.
192 * This certainly decreases memory consumption of the complete system.
193 *
194 * \ref LWESP_CFG_KEEP_ALIVE feature must be enable to properly handle all events
195 * \return \ref lwespOK on success, member of \ref lwespr_t otherwise
196 */
197lwespr_t
198station_manager_connect_to_access_point_async_init(void) {
199 /* Register system event function */
200 lwesp_evt_register(prv_evt_fn);
201
202 /*
203 * Start scanning process in non-blocking mode
204 *
205 * This is the only command being executed from non-callback mode,
206 * therefore it must be protected against other threads trying to access the same core
207 */
208 lwesp_core_lock();
209 prv_scan_ap_command();
210 lwesp_core_unlock();
211
212 /* Return all good, things will progress (from now-on) asynchronously */
213 return lwespOK;
214}
215
216/**
217 * \brief Connect to preferred access point in blocking mode
218 *
219 * This functionality can only be used if non-blocking approach is not used
220 *
221 * \note List of access points should be set by user in \ref ap_list structure
222 * \param[in] unlimited: When set to 1, function will block until SSID is found and connected
223 * \return \ref lwespOK on success, member of \ref lwespr_t enumeration otherwise
224 */
225lwespr_t
226station_manager_connect_to_preferred_access_point(uint8_t unlimited) {
227 lwespr_t eres;
228 uint8_t tried;
229
230 /*
231 * Scan for network access points
232 * In case we have access point,
233 * try to connect to known AP
234 */
235 do {
236 if (lwesp_sta_has_ip()) {
237 return lwespOK;
238 }
239
240 /* Scan for access points visible to ESP device */
241 printf("Scanning access points...\r\n");
242 if ((eres = prv_scan_ap_command_ex(1)) == lwespOK) {
243 tried = 0;
244
245 /* Print all access points found by ESP */
246 for (size_t i = 0; i < ap_list_scanned_len; i++) {
247 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);
248 }
249
250 /* Process array of preferred access points with array of found points */
251 for (size_t j = 0; j < LWESP_ARRAYSIZE(ap_list_preferred); j++) {
252
253 /* Go through all scanned list */
254 for (size_t i = 0; i < ap_list_scanned_len; i++) {
255
256 /* Try to find a match between preferred and scanned */
257 if (strncmp(ap_list_scanned[i].ssid, ap_list_preferred[j].ssid, strlen(ap_list_scanned[i].ssid)) == 0) {
258 tried = 1;
259 printf("Connecting to \"%s\" network...\r\n", ap_list_preferred[j].ssid);
260
261 /* Try to join to access point */
262 if ((eres = lwesp_sta_join(ap_list_preferred[j].ssid, ap_list_preferred[j].pass, NULL, NULL, NULL, 1)) == lwespOK) {
263 lwesp_ip_t ip;
264 uint8_t is_dhcp;
265
266 printf("Connected to %s network!\r\n", ap_list_preferred[j].ssid);
267
268 lwesp_sta_copy_ip(&ip, NULL, NULL, &is_dhcp);
269 utils_print_ip("Station IP address: ", &ip, "\r\n");
270 printf("; Is DHCP: %d\r\n", (int)is_dhcp);
271 return lwespOK;
272 } else {
273 printf("Connection error: %d\r\n", (int)eres);
274 }
275 }
276 }
277 }
278 if (!tried) {
279 printf("No access points available with preferred SSID!\r\nPlease check station_manager.c file and edit preferred SSID access points!\r\n");
280 }
281 } else if (eres == lwespERRNODEVICE) {
282 printf("Device is not present!\r\n");
283 break;
284 } else {
285 printf("Error on WIFI scan procedure!\r\n");
286 }
287 if (!unlimited) {
288 break;
289 }
290 } while (1);
291 return lwespERR;
292}
- 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 passwordmac – [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 neededevt_fn – [in] Callback function called when command has finished. Set to
NULL
when not usedevt_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.
-
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 or0
to disableevt_fn – [in] Callback function called when command has finished. Set to
NULL
when not usedevt_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
or0
to disable reconnect featurerep_cnt – [in] Repeat counter. Number of maximum tries for reconnect. Valid entries are
1-1000
or0
to always try. This parameter is only valid if interval is not0
evt_fn – [in] Callback function called when command has finished. Set to
NULL
when not usedevt_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 usedevt_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 gatewaynm – [in] Pointer to netmask address. Set to
NULL
to use default netmaskevt_fn – [in] Callback function called when command has finished. Set to
NULL
when not usedevt_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 usedevt_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 usedevt_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 addressgw – [out] Pointer to output gateway variable. Set to
NULL
if not interested in gateway addressnm – [out] Pointer to output netmask variable. Set to
NULL
if not interested in netmask addressis_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 filteraps – [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 usedevt_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 usedevt_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
-
lwesp_ip_t ip
-
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)