Skip to content

Wi-Fi autoconnect and title bar status #6473

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ Behavior
make each file independent from each other.

- ``boot.py`` runs only once on start up before
USB is initialized. This lays the ground work for configuring USB at
workflows are initialized. This lays the ground work for configuring USB at
startup rather than it being fixed. Since serial is not available,
output is written to ``boot_out.txt``.
- ``code.py`` (or ``main.py``) is run after every reload until it
Expand All @@ -135,7 +135,10 @@ Behavior
possible to fix code that causes nasty crashes by making it available through mass storage after
the crash. A reset (the button) is needed after it's fixed to get back into normal mode.
- RGB status LED indicating CircuitPython state.
- Re-runs ``code.py`` or other main file after file system writes over USB mass storage. (Disable with
- One green flash - code completed without error.
- Two red flashes - code ended due to an exception.
- Three yellow flashes - safe mode. May be due to CircuitPython internal error.
- Re-runs ``code.py`` or other main file after file system writes by a workflow. (Disable with
``supervisor.disable_autoreload()``)
- Autoreload is disabled while the REPL is active.
- Main is one of these: ``code.txt``, ``code.py``, ``main.py``,
Expand Down
40 changes: 40 additions & 0 deletions docs/environment.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Environment Variables
=====================

CircuitPython 8.0.0 introduces support for environment variables. Environment
variables are commonly used to store "secrets" such as Wi-Fi passwords and API
keys. This method *does not* make them secure. It only separates them from the
code.

CircuitPython supports these by mimicking the `dotenv <https://github.com/theskumar/python-dotenv>`_
CPython library. Other languages such as Javascript, PHP and Ruby also have
dotenv libraries.

These libraries store environment variables in a ``.env`` file. Here is a simple
example:

.. code-block:: bash

KEY1='value1'
# Comment
KEY2='value2
is multiple lines'

CircuitPython uses the ``.env`` at the drive root (no folder) as the environment.
User code can access the values from the file using `os.getenv()`. It is
recommended to save any values used repeatedly in a variable because `os.getenv()`
will parse the ``/.env`` on every access.

CircuitPython behavior
----------------------

CircuitPython will also read the environment to configure its behavior. Other
keys are ignored by CircuitPython. Here are the keys it uses:

CIRCUITPY_WIFI_PASSWORD
~~~~~~~~~~~~~~~~~~~~~~~
Wi-Fi password used to auto connect to CIRCUITPY_WIFI_SSID

CIRCUITPY_WIFI_SSID
~~~~~~~~~~~~~~~~~~~
Wi-Fi SSID to auto-connect to even if user code is not running.
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Full Table of Contents
supported_ports.rst
troubleshooting.rst
drivers.rst
environment.rst

.. toctree::
:maxdepth: 1
Expand Down
12 changes: 12 additions & 0 deletions locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,10 @@ msgstr ""
msgid "No I2C device at address: 0x%x"
msgstr ""

#: supervisor/shared/web_workflow/web_workflow.c
msgid "No IP"
msgstr ""

#: ports/espressif/common-hal/busio/SPI.c
#: ports/mimxrt10xx/common-hal/busio/SPI.c
msgid "No MISO Pin"
Expand Down Expand Up @@ -2254,6 +2258,10 @@ msgid ""
"To list built-in modules type `help(\"modules\")`.\n"
msgstr ""

#: supervisor/shared/web_workflow/web_workflow.c
msgid "Wi-Fi: "
msgstr ""

#: main.c
msgid "Woken up by alarm.\n"
msgstr ""
Expand Down Expand Up @@ -3579,6 +3587,10 @@ msgstr ""
msgid "odd-length string"
msgstr ""

#: supervisor/shared/web_workflow/web_workflow.c
msgid "off"
msgstr ""

#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c
msgid "offset is too large"
msgstr ""
Expand Down
33 changes: 18 additions & 15 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@
#include "shared-module/memorymonitor/__init__.h"
#endif

#if CIRCUITPY_SOCKETPOOL
#include "shared-bindings/socketpool/__init__.h"
#endif

#if CIRCUITPY_USB_HID
#include "shared-module/usb_hid/__init__.h"
#endif
Expand Down Expand Up @@ -290,6 +294,16 @@ STATIC void cleanup_after_vm(supervisor_allocation *heap, mp_obj_t exception) {
keypad_reset();
#endif

// Close user-initiated sockets.
#if CIRCUITPY_SOCKETPOOL
socketpool_user_reset();
#endif

// Turn off user initiated WiFi connections.
#if CIRCUITPY_WIFI
wifi_user_reset();
#endif

// reset_board_buses() first because it may release pins from the never_reset state, so that
// reset_port() can reset them.
#if CIRCUITPY_BOARD
Expand All @@ -303,6 +317,9 @@ STATIC void cleanup_after_vm(supervisor_allocation *heap, mp_obj_t exception) {
stop_mp();
free_memory(heap);
supervisor_move_memory();

// Let the workflows know we've reset in case they want to restart.
supervisor_workflow_reset();
}

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

run_boot_py(safe_mode);

// Start USB after giving boot.py a chance to tweak behavior.
#if CIRCUITPY_USB
// Setup USB connection after heap is available.
// It needs the heap to build descriptors.
usb_init();
#endif

// Set up any other serial connection.
serial_init();

#if CIRCUITPY_BLEIO
bleio_reset();
supervisor_bluetooth_enable_workflow();
supervisor_start_bluetooth();
#endif
supervisor_workflow_start();

// Boot script is finished, so now go into REPL or run code.py.
int exit_code = PYEXEC_FORCED_EXIT;
Expand Down
4 changes: 4 additions & 0 deletions ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ void board_init(void) {
true, // backlight_on_high
false, // SH1107_addressing
50000); // backlight pwm frequency

#if CIRCUITPY_DEBUG
common_hal_never_reset_pin(DEFAULT_UART_BUS_TX);
#endif
}

bool espressif_board_reset_pin_number(gpio_num_t pin_number) {
Expand Down
2 changes: 1 addition & 1 deletion ports/espressif/common-hal/socketpool/Socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

STATIC socketpool_socket_obj_t *open_socket_handles[CONFIG_LWIP_MAX_SOCKETS];

void socket_reset(void) {
void socket_user_reset(void) {
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_handles); i++) {
if (open_socket_handles[i]) {
if (open_socket_handles[i]->num > 0) {
Expand Down
2 changes: 1 addition & 1 deletion ports/espressif/common-hal/socketpool/Socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ typedef struct {
mp_uint_t timeout_ms;
} socketpool_socket_obj_t;

void socket_reset(void);
void socket_user_reset(void);
bool register_open_socket(socketpool_socket_obj_t *self);

#endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL_SOCKET_H
8 changes: 8 additions & 0 deletions ports/espressif/common-hal/socketpool/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include "shared-bindings/socketpool/__init__.h"

#include "common-hal/socketpool/Socket.h"

void socketpool_user_reset(void) {
socket_user_reset();
}
46 changes: 41 additions & 5 deletions ports/espressif/common-hal/wifi/Radio.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t
if (!common_hal_wifi_radio_get_enabled(self)) {
mp_raise_RuntimeError(translate("wifi is not enabled"));
}
wifi_config_t *config = &self->sta_config;

size_t timeout_ms = timeout * 1000;
uint32_t start_time = common_hal_time_monotonic_ms();
uint32_t end_time = start_time + timeout_ms;

EventBits_t bits;
// can't block since both bits are false after wifi_init
Expand All @@ -245,18 +250,37 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t
pdTRUE,
pdTRUE,
0);
if (((bits & WIFI_CONNECTED_BIT) != 0) &&
!((bits & WIFI_DISCONNECTED_BIT) != 0)) {
return WIFI_RADIO_ERROR_NONE;
bool connected = ((bits & WIFI_CONNECTED_BIT) != 0) &&
!((bits & WIFI_DISCONNECTED_BIT) != 0);
if (connected) {
// SSIDs are up to 32 bytes. Assume it is null terminated if it is less.
if (memcmp(ssid, config->sta.ssid, ssid_len) == 0 &&
(ssid_len == 32 || strlen((const char *)config->sta.ssid) == ssid_len)) {
// Already connected to the desired network.
return WIFI_RADIO_ERROR_NONE;
} else {
xEventGroupClearBits(self->event_group_handle, WIFI_DISCONNECTED_BIT);
// Trying to switch networks so disconnect first.
esp_wifi_disconnect();
do {
RUN_BACKGROUND_TASKS;
bits = xEventGroupWaitBits(self->event_group_handle,
WIFI_DISCONNECTED_BIT,
pdTRUE,
pdTRUE,
0);
} while ((bits & WIFI_DISCONNECTED_BIT) == 0 && !mp_hal_is_interrupted());
}
}
// explicitly clear bits since xEventGroupWaitBits may have timed out
xEventGroupClearBits(self->event_group_handle, WIFI_CONNECTED_BIT);
xEventGroupClearBits(self->event_group_handle, WIFI_DISCONNECTED_BIT);
set_mode_station(self, true);

wifi_config_t *config = &self->sta_config;
memcpy(&config->sta.ssid, ssid, ssid_len);
config->sta.ssid[ssid_len] = 0;
if (ssid_len < 32) {
config->sta.ssid[ssid_len] = 0;
}
memcpy(&config->sta.password, password, password_len);
config->sta.password[password_len] = 0;
config->sta.channel = channel;
Expand Down Expand Up @@ -289,6 +313,10 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t
pdTRUE,
pdTRUE,
0);
// Don't retry anymore if we're over our time budget.
if (self->retries_left > 0 && common_hal_time_monotonic_ms() > end_time) {
self->retries_left = 0;
}
} while ((bits & (WIFI_CONNECTED_BIT | WIFI_DISCONNECTED_BIT)) == 0 && !mp_hal_is_interrupted());
if ((bits & WIFI_DISCONNECTED_BIT) != 0) {
if (self->last_disconnect_reason == WIFI_REASON_AUTH_FAIL) {
Expand Down Expand Up @@ -368,6 +396,14 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_subnet_ap(wifi_radio_obj_t *self) {
return common_hal_ipaddress_new_ipv4address(self->ap_ip_info.netmask.addr);
}

uint32_t wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) {
if (!esp_netif_is_netif_up(self->netif)) {
return 0;
}
esp_netif_get_ip_info(self->netif, &self->ip_info);
return self->ip_info.ip.addr;
}

mp_obj_t common_hal_wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) {
if (!esp_netif_is_netif_up(self->netif)) {
return mp_const_none;
Expand Down
20 changes: 18 additions & 2 deletions ports/espressif/common-hal/wifi/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ wifi_radio_obj_t common_hal_wifi_radio_obj;

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

#include "supervisor/workflow.h"

static const char *TAG = "wifi";

static void event_handler(void *arg, esp_event_base_t event_base,
Expand Down Expand Up @@ -106,12 +108,19 @@ static void event_handler(void *arg, esp_event_base_t event_base,
radio->retries_left = radio->starting_retries;
xEventGroupSetBits(radio->event_group_handle, WIFI_CONNECTED_BIT);
}
supervisor_workflow_request_background();
}

static bool wifi_inited, wifi_ever_inited;
static bool wifi_inited;
static bool wifi_ever_inited;
static bool wifi_user_initiated;

void common_hal_wifi_init(void) {
void common_hal_wifi_init(bool user_initiated) {
if (wifi_inited) {
return;
}
wifi_inited = true;
wifi_user_initiated = user_initiated;
common_hal_wifi_radio_obj.base.type = &wifi_radio_type;

if (!wifi_ever_inited) {
Expand Down Expand Up @@ -157,6 +166,12 @@ void common_hal_wifi_init(void) {
common_hal_wifi_radio_set_enabled(self, true);
}

void wifi_user_reset(void) {
if (wifi_user_initiated) {
wifi_reset();
}
}

void wifi_reset(void) {
if (!wifi_inited) {
return;
Expand All @@ -176,6 +191,7 @@ void wifi_reset(void) {
esp_netif_destroy(radio->ap_netif);
radio->ap_netif = NULL;
wifi_inited = false;
supervisor_workflow_request_background();
}

void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t *esp_ip_address) {
Expand Down
8 changes: 0 additions & 8 deletions ports/espressif/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,14 +282,6 @@ void reset_port(void) {
#if CIRCUITPY_WATCHDOG
watchdog_reset();
#endif

#if CIRCUITPY_WIFI
wifi_reset();
#endif

#if CIRCUITPY_SOCKETPOOL
socket_reset();
#endif
}

void reset_to_bootloader(void) {
Expand Down
34 changes: 1 addition & 33 deletions ports/nrf/boards/bluemicro833/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,10 @@ MCU_CHIP = nrf52833

INTERNAL_FLASH_FILESYSTEM = 1

CIRCUITPY_AESIO = 0
CIRCUITPY_ALARM = 0
CIRCUITPY_AUDIOBUSIO = 0
#CIRCUITPY_AUDIOCORE = 0
#CIRCUITPY_AUDIOIO = 0
CIRCUITPY_AUDIOMIXER = 0
CIRCUITPY_AUDIOMP3 = 0
CIRCUITPY_BINASCII = 0
CIRCUITPY_BITBANGIO = 0
CIRCUITPY_BITMAPTOOLS = 0
CIRCUITPY_BUILTINS_POW3=0
CIRCUITPY_BUSDEVICE = 0
CIRCUITPY_COUNTIO = 0
CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_FREQUENCYIO = 0
CIRCUITPY_GETPASS = 0
CIRCUITPY_I2CPERIPHERAL = 0
CIRCUITPY_JSON = 0
CIRCUITPY_KEYPAD = 1
CIRCUITPY_MSGPACK = 0
#CIRCUITPY_NEOPIXEL_WRITE = 1
CIRCUITPY_ONEWIREIO = 0
CIRCUITPY_NVM = 0
CIRCUITPY_ONEWIREIO = 0
CIRCUITPY_PIXELBUF = 1
CIRCUITPY_PULSEIO = 1
CIRCUITPY_RE = 0
CIRCUITPY_RGBMATRIX = 0
CIRCUITPY_SDCARDIO = 0
CIRCUITPY_SYNTHIO = 0
CIRCUITPY_TRACEBACK = 0
CIRCUITPY_TOUCHIO = 0
CIRCUITPY_TRACEBACK = 0
CIRCUITPY_ULAB = 0
CIRCUITPY_USB_MIDI = 0
CIRCUITPY_VECTORIO = 0
CIRCUITPY_ZLIB = 0

MICROPY_PY_ASYNC_AWAIT = 0
Loading