Skip to content

Commit 5c941ca

Browse files
authored
Merge pull request #6473 from tannewt/auto_wifi
Wi-Fi autoconnect and title bar status
2 parents ab346a2 + 0c418e9 commit 5c941ca

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+623
-258
lines changed

README.rst

+5-2
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ Behavior
120120
make each file independent from each other.
121121

122122
- ``boot.py`` runs only once on start up before
123-
USB is initialized. This lays the ground work for configuring USB at
123+
workflows are initialized. This lays the ground work for configuring USB at
124124
startup rather than it being fixed. Since serial is not available,
125125
output is written to ``boot_out.txt``.
126126
- ``code.py`` (or ``main.py``) is run after every reload until it
@@ -135,7 +135,10 @@ Behavior
135135
possible to fix code that causes nasty crashes by making it available through mass storage after
136136
the crash. A reset (the button) is needed after it's fixed to get back into normal mode.
137137
- RGB status LED indicating CircuitPython state.
138-
- Re-runs ``code.py`` or other main file after file system writes over USB mass storage. (Disable with
138+
- One green flash - code completed without error.
139+
- Two red flashes - code ended due to an exception.
140+
- Three yellow flashes - safe mode. May be due to CircuitPython internal error.
141+
- Re-runs ``code.py`` or other main file after file system writes by a workflow. (Disable with
139142
``supervisor.disable_autoreload()``)
140143
- Autoreload is disabled while the REPL is active.
141144
- Main is one of these: ``code.txt``, ``code.py``, ``main.py``,

docs/environment.rst

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
Environment Variables
2+
=====================
3+
4+
CircuitPython 8.0.0 introduces support for environment variables. Environment
5+
variables are commonly used to store "secrets" such as Wi-Fi passwords and API
6+
keys. This method *does not* make them secure. It only separates them from the
7+
code.
8+
9+
CircuitPython supports these by mimicking the `dotenv <https://github.com/theskumar/python-dotenv>`_
10+
CPython library. Other languages such as Javascript, PHP and Ruby also have
11+
dotenv libraries.
12+
13+
These libraries store environment variables in a ``.env`` file. Here is a simple
14+
example:
15+
16+
.. code-block:: bash
17+
18+
KEY1='value1'
19+
# Comment
20+
KEY2='value2
21+
is multiple lines'
22+
23+
CircuitPython uses the ``.env`` at the drive root (no folder) as the environment.
24+
User code can access the values from the file using `os.getenv()`. It is
25+
recommended to save any values used repeatedly in a variable because `os.getenv()`
26+
will parse the ``/.env`` on every access.
27+
28+
CircuitPython behavior
29+
----------------------
30+
31+
CircuitPython will also read the environment to configure its behavior. Other
32+
keys are ignored by CircuitPython. Here are the keys it uses:
33+
34+
CIRCUITPY_WIFI_PASSWORD
35+
~~~~~~~~~~~~~~~~~~~~~~~
36+
Wi-Fi password used to auto connect to CIRCUITPY_WIFI_SSID
37+
38+
CIRCUITPY_WIFI_SSID
39+
~~~~~~~~~~~~~~~~~~~
40+
Wi-Fi SSID to auto-connect to even if user code is not running.

docs/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Full Table of Contents
2222
supported_ports.rst
2323
troubleshooting.rst
2424
drivers.rst
25+
environment.rst
2526

2627
.. toctree::
2728
:maxdepth: 1

locale/circuitpython.pot

+12
Original file line numberDiff line numberDiff line change
@@ -1375,6 +1375,10 @@ msgstr ""
13751375
msgid "No I2C device at address: 0x%x"
13761376
msgstr ""
13771377

1378+
#: supervisor/shared/web_workflow/web_workflow.c
1379+
msgid "No IP"
1380+
msgstr ""
1381+
13781382
#: ports/espressif/common-hal/busio/SPI.c
13791383
#: ports/mimxrt10xx/common-hal/busio/SPI.c
13801384
msgid "No MISO Pin"
@@ -2254,6 +2258,10 @@ msgid ""
22542258
"To list built-in modules type `help(\"modules\")`.\n"
22552259
msgstr ""
22562260

2261+
#: supervisor/shared/web_workflow/web_workflow.c
2262+
msgid "Wi-Fi: "
2263+
msgstr ""
2264+
22572265
#: main.c
22582266
msgid "Woken up by alarm.\n"
22592267
msgstr ""
@@ -3579,6 +3587,10 @@ msgstr ""
35793587
msgid "odd-length string"
35803588
msgstr ""
35813589

3590+
#: supervisor/shared/web_workflow/web_workflow.c
3591+
msgid "off"
3592+
msgstr ""
3593+
35823594
#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c
35833595
msgid "offset is too large"
35843596
msgstr ""

main.c

+18-15
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@
101101
#include "shared-module/memorymonitor/__init__.h"
102102
#endif
103103

104+
#if CIRCUITPY_SOCKETPOOL
105+
#include "shared-bindings/socketpool/__init__.h"
106+
#endif
107+
104108
#if CIRCUITPY_USB_HID
105109
#include "shared-module/usb_hid/__init__.h"
106110
#endif
@@ -290,6 +294,16 @@ STATIC void cleanup_after_vm(supervisor_allocation *heap, mp_obj_t exception) {
290294
keypad_reset();
291295
#endif
292296

297+
// Close user-initiated sockets.
298+
#if CIRCUITPY_SOCKETPOOL
299+
socketpool_user_reset();
300+
#endif
301+
302+
// Turn off user initiated WiFi connections.
303+
#if CIRCUITPY_WIFI
304+
wifi_user_reset();
305+
#endif
306+
293307
// reset_board_buses() first because it may release pins from the never_reset state, so that
294308
// reset_port() can reset them.
295309
#if CIRCUITPY_BOARD
@@ -303,6 +317,9 @@ STATIC void cleanup_after_vm(supervisor_allocation *heap, mp_obj_t exception) {
303317
stop_mp();
304318
free_memory(heap);
305319
supervisor_move_memory();
320+
321+
// Let the workflows know we've reset in case they want to restart.
322+
supervisor_workflow_reset();
306323
}
307324

308325
STATIC void print_code_py_status_message(safe_mode_t safe_mode) {
@@ -889,21 +906,7 @@ int __attribute__((used)) main(void) {
889906

890907
run_boot_py(safe_mode);
891908

892-
// Start USB after giving boot.py a chance to tweak behavior.
893-
#if CIRCUITPY_USB
894-
// Setup USB connection after heap is available.
895-
// It needs the heap to build descriptors.
896-
usb_init();
897-
#endif
898-
899-
// Set up any other serial connection.
900-
serial_init();
901-
902-
#if CIRCUITPY_BLEIO
903-
bleio_reset();
904-
supervisor_bluetooth_enable_workflow();
905-
supervisor_start_bluetooth();
906-
#endif
909+
supervisor_workflow_start();
907910

908911
// Boot script is finished, so now go into REPL or run code.py.
909912
int exit_code = PYEXEC_FORCED_EXIT;

ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c

+4
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ void board_init(void) {
117117
true, // backlight_on_high
118118
false, // SH1107_addressing
119119
50000); // backlight pwm frequency
120+
121+
#if CIRCUITPY_DEBUG
122+
common_hal_never_reset_pin(DEFAULT_UART_BUS_TX);
123+
#endif
120124
}
121125

122126
bool espressif_board_reset_pin_number(gpio_num_t pin_number) {

ports/espressif/common-hal/socketpool/Socket.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
STATIC socketpool_socket_obj_t *open_socket_handles[CONFIG_LWIP_MAX_SOCKETS];
4141

42-
void socket_reset(void) {
42+
void socket_user_reset(void) {
4343
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_handles); i++) {
4444
if (open_socket_handles[i]) {
4545
if (open_socket_handles[i]->num > 0) {

ports/espressif/common-hal/socketpool/Socket.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ typedef struct {
4545
mp_uint_t timeout_ms;
4646
} socketpool_socket_obj_t;
4747

48-
void socket_reset(void);
48+
void socket_user_reset(void);
4949
bool register_open_socket(socketpool_socket_obj_t *self);
5050

5151
#endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL_SOCKET_H

ports/espressif/common-hal/socketpool/__init__.c

+8
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,11 @@
2323
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2424
* THE SOFTWARE.
2525
*/
26+
27+
#include "shared-bindings/socketpool/__init__.h"
28+
29+
#include "common-hal/socketpool/Socket.h"
30+
31+
void socketpool_user_reset(void) {
32+
socket_user_reset();
33+
}

ports/espressif/common-hal/wifi/Radio.c

+41-5
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,11 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t
236236
if (!common_hal_wifi_radio_get_enabled(self)) {
237237
mp_raise_RuntimeError(translate("wifi is not enabled"));
238238
}
239+
wifi_config_t *config = &self->sta_config;
240+
241+
size_t timeout_ms = timeout * 1000;
242+
uint32_t start_time = common_hal_time_monotonic_ms();
243+
uint32_t end_time = start_time + timeout_ms;
239244

240245
EventBits_t bits;
241246
// can't block since both bits are false after wifi_init
@@ -245,18 +250,37 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t
245250
pdTRUE,
246251
pdTRUE,
247252
0);
248-
if (((bits & WIFI_CONNECTED_BIT) != 0) &&
249-
!((bits & WIFI_DISCONNECTED_BIT) != 0)) {
250-
return WIFI_RADIO_ERROR_NONE;
253+
bool connected = ((bits & WIFI_CONNECTED_BIT) != 0) &&
254+
!((bits & WIFI_DISCONNECTED_BIT) != 0);
255+
if (connected) {
256+
// SSIDs are up to 32 bytes. Assume it is null terminated if it is less.
257+
if (memcmp(ssid, config->sta.ssid, ssid_len) == 0 &&
258+
(ssid_len == 32 || strlen((const char *)config->sta.ssid) == ssid_len)) {
259+
// Already connected to the desired network.
260+
return WIFI_RADIO_ERROR_NONE;
261+
} else {
262+
xEventGroupClearBits(self->event_group_handle, WIFI_DISCONNECTED_BIT);
263+
// Trying to switch networks so disconnect first.
264+
esp_wifi_disconnect();
265+
do {
266+
RUN_BACKGROUND_TASKS;
267+
bits = xEventGroupWaitBits(self->event_group_handle,
268+
WIFI_DISCONNECTED_BIT,
269+
pdTRUE,
270+
pdTRUE,
271+
0);
272+
} while ((bits & WIFI_DISCONNECTED_BIT) == 0 && !mp_hal_is_interrupted());
273+
}
251274
}
252275
// explicitly clear bits since xEventGroupWaitBits may have timed out
253276
xEventGroupClearBits(self->event_group_handle, WIFI_CONNECTED_BIT);
254277
xEventGroupClearBits(self->event_group_handle, WIFI_DISCONNECTED_BIT);
255278
set_mode_station(self, true);
256279

257-
wifi_config_t *config = &self->sta_config;
258280
memcpy(&config->sta.ssid, ssid, ssid_len);
259-
config->sta.ssid[ssid_len] = 0;
281+
if (ssid_len < 32) {
282+
config->sta.ssid[ssid_len] = 0;
283+
}
260284
memcpy(&config->sta.password, password, password_len);
261285
config->sta.password[password_len] = 0;
262286
config->sta.channel = channel;
@@ -289,6 +313,10 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t
289313
pdTRUE,
290314
pdTRUE,
291315
0);
316+
// Don't retry anymore if we're over our time budget.
317+
if (self->retries_left > 0 && common_hal_time_monotonic_ms() > end_time) {
318+
self->retries_left = 0;
319+
}
292320
} while ((bits & (WIFI_CONNECTED_BIT | WIFI_DISCONNECTED_BIT)) == 0 && !mp_hal_is_interrupted());
293321
if ((bits & WIFI_DISCONNECTED_BIT) != 0) {
294322
if (self->last_disconnect_reason == WIFI_REASON_AUTH_FAIL) {
@@ -368,6 +396,14 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_subnet_ap(wifi_radio_obj_t *self) {
368396
return common_hal_ipaddress_new_ipv4address(self->ap_ip_info.netmask.addr);
369397
}
370398

399+
uint32_t wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) {
400+
if (!esp_netif_is_netif_up(self->netif)) {
401+
return 0;
402+
}
403+
esp_netif_get_ip_info(self->netif, &self->ip_info);
404+
return self->ip_info.ip.addr;
405+
}
406+
371407
mp_obj_t common_hal_wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) {
372408
if (!esp_netif_is_netif_up(self->netif)) {
373409
return mp_const_none;

ports/espressif/common-hal/wifi/__init__.c

+18-2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ wifi_radio_obj_t common_hal_wifi_radio_obj;
4242

4343
#include "components/log/include/esp_log.h"
4444

45+
#include "supervisor/workflow.h"
46+
4547
static const char *TAG = "wifi";
4648

4749
static void event_handler(void *arg, esp_event_base_t event_base,
@@ -106,12 +108,19 @@ static void event_handler(void *arg, esp_event_base_t event_base,
106108
radio->retries_left = radio->starting_retries;
107109
xEventGroupSetBits(radio->event_group_handle, WIFI_CONNECTED_BIT);
108110
}
111+
supervisor_workflow_request_background();
109112
}
110113

111-
static bool wifi_inited, wifi_ever_inited;
114+
static bool wifi_inited;
115+
static bool wifi_ever_inited;
116+
static bool wifi_user_initiated;
112117

113-
void common_hal_wifi_init(void) {
118+
void common_hal_wifi_init(bool user_initiated) {
119+
if (wifi_inited) {
120+
return;
121+
}
114122
wifi_inited = true;
123+
wifi_user_initiated = user_initiated;
115124
common_hal_wifi_radio_obj.base.type = &wifi_radio_type;
116125

117126
if (!wifi_ever_inited) {
@@ -157,6 +166,12 @@ void common_hal_wifi_init(void) {
157166
common_hal_wifi_radio_set_enabled(self, true);
158167
}
159168

169+
void wifi_user_reset(void) {
170+
if (wifi_user_initiated) {
171+
wifi_reset();
172+
}
173+
}
174+
160175
void wifi_reset(void) {
161176
if (!wifi_inited) {
162177
return;
@@ -176,6 +191,7 @@ void wifi_reset(void) {
176191
esp_netif_destroy(radio->ap_netif);
177192
radio->ap_netif = NULL;
178193
wifi_inited = false;
194+
supervisor_workflow_request_background();
179195
}
180196

181197
void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t *esp_ip_address) {

ports/espressif/supervisor/port.c

-8
Original file line numberDiff line numberDiff line change
@@ -282,14 +282,6 @@ void reset_port(void) {
282282
#if CIRCUITPY_WATCHDOG
283283
watchdog_reset();
284284
#endif
285-
286-
#if CIRCUITPY_WIFI
287-
wifi_reset();
288-
#endif
289-
290-
#if CIRCUITPY_SOCKETPOOL
291-
socket_reset();
292-
#endif
293285
}
294286

295287
void reset_to_bootloader(void) {

ports/nrf/boards/bluemicro833/mpconfigboard.mk

+1-33
Original file line numberDiff line numberDiff line change
@@ -7,42 +7,10 @@ MCU_CHIP = nrf52833
77

88
INTERNAL_FLASH_FILESYSTEM = 1
99

10-
CIRCUITPY_AESIO = 0
11-
CIRCUITPY_ALARM = 0
1210
CIRCUITPY_AUDIOBUSIO = 0
13-
#CIRCUITPY_AUDIOCORE = 0
14-
#CIRCUITPY_AUDIOIO = 0
1511
CIRCUITPY_AUDIOMIXER = 0
16-
CIRCUITPY_AUDIOMP3 = 0
17-
CIRCUITPY_BINASCII = 0
18-
CIRCUITPY_BITBANGIO = 0
19-
CIRCUITPY_BITMAPTOOLS = 0
20-
CIRCUITPY_BUILTINS_POW3=0
21-
CIRCUITPY_BUSDEVICE = 0
22-
CIRCUITPY_COUNTIO = 0
23-
CIRCUITPY_DISPLAYIO = 0
24-
CIRCUITPY_FRAMEBUFFERIO = 0
25-
CIRCUITPY_FREQUENCYIO = 0
26-
CIRCUITPY_GETPASS = 0
27-
CIRCUITPY_I2CPERIPHERAL = 0
28-
CIRCUITPY_JSON = 0
2912
CIRCUITPY_KEYPAD = 1
30-
CIRCUITPY_MSGPACK = 0
31-
#CIRCUITPY_NEOPIXEL_WRITE = 1
32-
CIRCUITPY_ONEWIREIO = 0
3313
CIRCUITPY_NVM = 0
14+
CIRCUITPY_ONEWIREIO = 0
3415
CIRCUITPY_PIXELBUF = 1
35-
CIRCUITPY_PULSEIO = 1
36-
CIRCUITPY_RE = 0
37-
CIRCUITPY_RGBMATRIX = 0
38-
CIRCUITPY_SDCARDIO = 0
39-
CIRCUITPY_SYNTHIO = 0
40-
CIRCUITPY_TRACEBACK = 0
4116
CIRCUITPY_TOUCHIO = 0
42-
CIRCUITPY_TRACEBACK = 0
43-
CIRCUITPY_ULAB = 0
44-
CIRCUITPY_USB_MIDI = 0
45-
CIRCUITPY_VECTORIO = 0
46-
CIRCUITPY_ZLIB = 0
47-
48-
MICROPY_PY_ASYNC_AWAIT = 0

0 commit comments

Comments
 (0)