Skip to content

Commit de7eb99

Browse files
committed
esp32/modsmartconfig: Add 'smartconfig' module to esp32 port.
Signed-off-by: Walkline Wang <walkline@gmail.com>
1 parent 0432f73 commit de7eb99

File tree

5 files changed

+385
-0
lines changed

5 files changed

+385
-0
lines changed

docs/library/index.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,11 @@ The following libraries are specific to the ESP8266 and ESP32.
170170
espnow.rst
171171

172172

173+
.. toctree::
174+
:maxdepth: 1
175+
176+
smartconfig.rst
177+
173178
Libraries specific to the RP2040
174179
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
175180

docs/library/smartconfig.rst

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
:mod:`smartconfig` --- support for the SmartConfig provisioning protocol
2+
========================================================================
3+
4+
.. module:: smartconfig
5+
:synopsis: SmartConfig provisioning protocol support
6+
7+
This module provides an interface to the SmartConfig provisioning protocol
8+
provided by Espressif on ESP32 devices (`API docs <https://docs.espressif.com/
9+
projects/esp-idf/en/latest/esp32/api-reference/network/esp_smartconfig.html>`_).
10+
11+
Introduction
12+
------------
13+
14+
The SmartConfig\ :sup:`TM` is a provisioning technology developed by TI to
15+
connect a new Wi-Fi device to a Wi-Fi network. It uses a mobile application to
16+
broadcast the network credentials from a smartphone, or a tablet, to an
17+
un-provisioned Wi-Fi device.
18+
19+
The advantage of this technology is that the device does not need to directly
20+
know SSID or password of an Access Point (AP). This information is provided
21+
using the smartphone. This is particularly important to headless device and
22+
systems, due to their lack of a user interface.
23+
24+
A simple example would be::
25+
26+
import network, time
27+
import smartconfig
28+
29+
# A WLAN interface must be instancing to start smartconfig progress
30+
sta = network.WLAN(network.STA_IF)
31+
sta.active(True)
32+
33+
smartconfig.type(smartconfig.TYPE_ESPTOUCH_AIRKISS)
34+
35+
smartconfig.start()
36+
37+
while not smartconfig.done():
38+
time.sleep_ms(100)
39+
40+
print(smartconfig.info())
41+
# (ssid, password, bssid, type[, rvd_data])
42+
43+
smartconfig.stop()
44+
45+
Functions
46+
---------
47+
48+
.. function:: start()
49+
50+
Start the SmartConfig process.
51+
52+
After received the broadcast data, it will try to use the data to connect
53+
to the AP, the ``smartconfig.done()`` function returns ``True`` regardless
54+
of whether the connection is successful or not.
55+
56+
**Note:** This function automatically calls the ``smartconfig.stop()``
57+
function first.
58+
59+
.. function:: stop()
60+
61+
Stop the SmartConfig process.
62+
63+
.. function:: done()
64+
65+
Returns ``True`` if the SmartConfig process completed, and ``False`` for
66+
otherwise.
67+
68+
**Note:** If returns ``True``, it will automatically calls the
69+
``smartconfig.stop()`` function.
70+
71+
.. function:: info()
72+
73+
Returns a 4 or 5-tuple ``(ssid, password, bssid, type[, rvd_data])``.
74+
75+
**Note:** ``rvd_data`` is the custom data for EspTouch V2 protocol type.
76+
77+
.. function:: ssid()
78+
79+
Returns the received ``ssid`` as a string.
80+
81+
.. function:: password()
82+
83+
Returns the received ``password`` as a string.
84+
85+
.. function:: bssid()
86+
87+
Returns the received ``bssid`` as a ``bytes``.
88+
89+
.. function:: type([type])
90+
91+
Get or set SmartConfig protocol type.
92+
93+
You must set a protocol type for receiving data that broadcast by your phone
94+
over the same protocol, usually set to ``smartconfig.TYPE_ESPTOUCH_AIRKISS``,
95+
which can cover mostly of the application scenarios.
96+
97+
When SmartConfig process done, you can get the protocol type used by the
98+
phone.
99+
100+
.. function:: rvd_data()
101+
102+
Returns the received ``rvd_data`` as a ``bytes``.
103+
104+
Constants
105+
---------
106+
107+
.. data:: TYPE_ESPTOUCH
108+
TYPE_AIRKISS
109+
TYPE_ESPTOUCH_AIRKISS
110+
TYPE_ESPTOUCH_V2
111+
112+
SmartConfig protocol types.

ports/esp32/esp32_common.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ list(APPEND MICROPY_SOURCE_PORT
8686
machine_rtc.c
8787
machine_sdcard.c
8888
modespnow.c
89+
modsmartconfig.c
8990
)
9091
list(TRANSFORM MICROPY_SOURCE_PORT PREPEND ${MICROPY_PORT_DIR}/)
9192
list(APPEND MICROPY_SOURCE_PORT ${CMAKE_BINARY_DIR}/pins.c)

ports/esp32/modsmartconfig.c

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
#include <string.h>
2+
3+
#include "py/runtime.h"
4+
5+
#include "freertos/FreeRTOS.h"
6+
#include "freertos/task.h"
7+
#include "freertos/event_groups.h"
8+
9+
#include "esp_wifi.h"
10+
#include "esp_event.h"
11+
#include "esp_log.h"
12+
#include "esp_smartconfig.h"
13+
14+
#include "mphalport.h"
15+
#include "modsmartconfig.h"
16+
17+
static EventGroupHandle_t wifi_event_group;
18+
19+
static bool smartconfig_process_done = false;
20+
21+
/* info variables */
22+
static uint8_t ssid[33] = {0};
23+
static uint8_t bssid[6] = {0};
24+
static uint8_t password[65] = {0};
25+
static uint8_t rvd_data[33] = {0};
26+
static int type = SC_TYPE_ESPTOUCH_AIRKISS;
27+
28+
/* event_handler used for esp_event_handler_register() */
29+
static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
30+
if (event_base == WIFI_EVENT &&
31+
event_id == WIFI_EVENT_STA_START) {
32+
xTaskCreate(smartconfig_task, "smartconfig_task", 4096, NULL, 3, NULL);
33+
} else if (event_base == WIFI_EVENT &&
34+
event_id == WIFI_EVENT_STA_DISCONNECTED) {
35+
// wrong password or other situations may occurs this event
36+
xEventGroupSetBits(wifi_event_group, SMARTCONFIG_DONE_BIT);
37+
} else if (event_base == IP_EVENT &&
38+
event_id == IP_EVENT_STA_GOT_IP) {
39+
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
40+
} else if (event_base == SC_EVENT &&
41+
event_id == SC_EVENT_SCAN_DONE) {
42+
ESP_LOGI(TAG, "Scan done");
43+
} else if (event_base == SC_EVENT &&
44+
event_id == SC_EVENT_GOT_SSID_PSWD) {
45+
smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
46+
wifi_config_t wifi_config;
47+
48+
bzero(&wifi_config, sizeof(wifi_config_t));
49+
memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
50+
memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
51+
wifi_config.sta.bssid_set = evt->bssid_set;
52+
53+
if (wifi_config.sta.bssid_set == true) {
54+
memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
55+
}
56+
57+
memcpy(ssid, evt->ssid, sizeof(evt->ssid));
58+
memcpy(bssid, evt->bssid, sizeof(evt->bssid));
59+
memcpy(password, evt->password, sizeof(evt->password));
60+
type = evt->type;
61+
62+
if (evt->type == SC_TYPE_ESPTOUCH_V2) {
63+
check_esp_err(esp_smartconfig_get_rvd_data(rvd_data, sizeof(rvd_data)));
64+
}
65+
66+
check_esp_err(esp_wifi_disconnect());
67+
check_esp_err(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
68+
69+
ESP_LOGI(TAG, "Try to connect to ap");
70+
71+
esp_wifi_connect();
72+
} else if (event_base == SC_EVENT &&
73+
event_id == SC_EVENT_SEND_ACK_DONE) {
74+
xEventGroupSetBits(wifi_event_group, SMARTCONFIG_DONE_BIT);
75+
ESP_LOGI(TAG, "Send ack done");
76+
}
77+
}
78+
79+
/* task function used for xTaskCreate() */
80+
static void smartconfig_task(void *param) {
81+
check_esp_err(esp_smartconfig_set_type(type));
82+
smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
83+
check_esp_err(esp_smartconfig_start(&cfg));
84+
85+
EventBits_t uxBits;
86+
87+
while (1) {
88+
uxBits = xEventGroupWaitBits(
89+
wifi_event_group,
90+
CONNECTED_BIT | SMARTCONFIG_DONE_BIT,
91+
true, false, portMAX_DELAY
92+
);
93+
94+
if (uxBits & CONNECTED_BIT) {
95+
ESP_LOGI(TAG, "Connected to ap");
96+
}
97+
98+
if (uxBits & SMARTCONFIG_DONE_BIT) {
99+
ESP_LOGI(TAG, "Smartconfig done");
100+
smartconfig_process_done = true;
101+
smartconfig_stop();
102+
vTaskDelete(NULL);
103+
}
104+
}
105+
}
106+
107+
/*
108+
* initialize info variables,
109+
* register event handlers and restart wifi
110+
*/
111+
static void smartconfig_init(void) {
112+
smartconfig_process_done = false;
113+
114+
memset(ssid, 0, sizeof(ssid));
115+
memset(bssid, 0, sizeof(bssid));
116+
memset(password, 0, sizeof(password));
117+
memset(rvd_data, 0, sizeof(rvd_data));
118+
119+
wifi_event_group = xEventGroupCreate();
120+
121+
esp_err_t err = esp_wifi_stop();
122+
if (err == ESP_ERR_WIFI_NOT_INIT) {
123+
return;
124+
}
125+
check_esp_err(err);
126+
127+
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
128+
check_esp_err(esp_wifi_init(&cfg));
129+
130+
check_esp_err(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
131+
check_esp_err(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
132+
check_esp_err(esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
133+
134+
check_esp_err(esp_wifi_set_mode(WIFI_MODE_STA));
135+
check_esp_err(esp_wifi_start());
136+
}
137+
138+
/*
139+
* get/set smartconfig protocol type
140+
*
141+
* smartconfig.type([type])
142+
*/
143+
STATIC mp_obj_t smartconfig_type(size_t n_args, const mp_obj_t *args) {
144+
if (n_args == 0 || args[0] == mp_const_none) {
145+
return mp_obj_new_int(type);
146+
} else {
147+
if (mp_obj_is_integer(args[0])) {
148+
type = mp_obj_get_int(args[0]);
149+
150+
if (type > SC_TYPE_ESPTOUCH_V2 || type < SC_TYPE_ESPTOUCH) {
151+
type = SC_TYPE_ESPTOUCH_AIRKISS;
152+
}
153+
} else {
154+
mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments"));
155+
}
156+
}
157+
158+
return mp_const_none;
159+
}
160+
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(smartconfig_type_obj, 0, 1, smartconfig_type);
161+
162+
STATIC mp_obj_t smartconfig_start(void) {
163+
smartconfig_stop();
164+
smartconfig_init();
165+
166+
return mp_const_none;
167+
}
168+
STATIC MP_DEFINE_CONST_FUN_OBJ_0(smartconfig_start_obj, smartconfig_start);
169+
170+
STATIC mp_obj_t smartconfig_stop(void) {
171+
esp_smartconfig_stop();
172+
173+
check_esp_err(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler));
174+
check_esp_err(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler));
175+
check_esp_err(esp_event_handler_unregister(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler));
176+
177+
return mp_const_none;
178+
}
179+
STATIC MP_DEFINE_CONST_FUN_OBJ_0(smartconfig_stop_obj, smartconfig_stop);
180+
181+
STATIC mp_obj_t smartconfig_done(void) {
182+
return mp_obj_new_bool(smartconfig_process_done);
183+
}
184+
STATIC MP_DEFINE_CONST_FUN_OBJ_0(smartconfig_done_obj, smartconfig_done);
185+
186+
/*
187+
* get smartconfig info
188+
*
189+
* return: tuple(ssid, password, bssid, type[, rvd_data])
190+
* rvd_data - EspTouch V2 reserved data
191+
*/
192+
STATIC mp_obj_t smartconfig_info(void) {
193+
mp_obj_t info[] = {
194+
mp_obj_new_str((const char *)ssid, strlen((const char *)ssid)),
195+
mp_obj_new_str((const char *)password, strlen((const char *)password)),
196+
mp_obj_new_bytes(bssid, sizeof(bssid)),
197+
mp_obj_new_int(type),
198+
mp_obj_new_bytes(rvd_data, strlen((const char *)rvd_data))
199+
};
200+
201+
if (rvd_data[0] == 0x00) {
202+
return mp_obj_new_tuple(4, info);
203+
}
204+
205+
return mp_obj_new_tuple(5, info);
206+
}
207+
STATIC MP_DEFINE_CONST_FUN_OBJ_0(smartconfig_info_obj, smartconfig_info);
208+
209+
/* get ssid */
210+
STATIC mp_obj_t smartconfig_ssid(void) {
211+
return mp_obj_new_str((const char *)ssid, strlen((const char *)ssid));
212+
}
213+
STATIC MP_DEFINE_CONST_FUN_OBJ_0(smartconfig_ssid_obj, smartconfig_ssid);
214+
215+
/* get password */
216+
STATIC mp_obj_t smartconfig_password(void) {
217+
return mp_obj_new_str((const char *)password, strlen((const char *)password));
218+
}
219+
STATIC MP_DEFINE_CONST_FUN_OBJ_0(smartconfig_password_obj, smartconfig_password);
220+
221+
/* get bssid */
222+
STATIC mp_obj_t smartconfig_bssid(void) {
223+
return mp_obj_new_bytes(bssid, sizeof(bssid));
224+
}
225+
STATIC MP_DEFINE_CONST_FUN_OBJ_0(smartconfig_bssid_obj, smartconfig_bssid);
226+
227+
/* get rvd_data */
228+
STATIC mp_obj_t smartconfig_rvd_data(void) {
229+
return mp_obj_new_bytes(rvd_data, strlen((const char *)rvd_data));
230+
}
231+
STATIC MP_DEFINE_CONST_FUN_OBJ_0(smartconfig_rvd_data_obj, smartconfig_rvd_data);
232+
233+
STATIC const mp_rom_map_elem_t smartconfig_module_globals_table[] = {
234+
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_smartconfig)},
235+
{MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&smartconfig_type_obj)},
236+
{MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&smartconfig_start_obj)},
237+
{MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&smartconfig_stop_obj)},
238+
{MP_ROM_QSTR(MP_QSTR_done), MP_ROM_PTR(&smartconfig_done_obj)},
239+
{MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&smartconfig_info_obj)},
240+
{MP_ROM_QSTR(MP_QSTR_ssid), MP_ROM_PTR(&smartconfig_ssid_obj)},
241+
{MP_ROM_QSTR(MP_QSTR_password), MP_ROM_PTR(&smartconfig_password_obj)},
242+
{MP_ROM_QSTR(MP_QSTR_bssid), MP_ROM_PTR(&smartconfig_bssid_obj)},
243+
{MP_ROM_QSTR(MP_QSTR_rvd_data), MP_ROM_PTR(&smartconfig_rvd_data_obj)},
244+
{MP_ROM_QSTR(MP_QSTR_TYPE_ESPTOUCH), MP_ROM_INT(SC_TYPE_ESPTOUCH)},
245+
{MP_ROM_QSTR(MP_QSTR_TYPE_AIRKISS), MP_ROM_INT(SC_TYPE_AIRKISS)},
246+
{MP_ROM_QSTR(MP_QSTR_TYPE_ESPTOUCH_AIRKISS), MP_ROM_INT(SC_TYPE_ESPTOUCH_AIRKISS)},
247+
{MP_ROM_QSTR(MP_QSTR_TYPE_ESPTOUCH_V2), MP_ROM_INT(SC_TYPE_ESPTOUCH_V2)},
248+
};
249+
STATIC MP_DEFINE_CONST_DICT(smartconfig_module_globals, smartconfig_module_globals_table);
250+
251+
const mp_obj_module_t smartconfig_user_cmodule = {
252+
.base = {&mp_type_module},
253+
.globals = (mp_obj_dict_t *)&smartconfig_module_globals,
254+
};
255+
256+
MP_REGISTER_MODULE(MP_QSTR_smartconfig, smartconfig_user_cmodule);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy