Skip to content

Commit

Permalink
feat(console): Console for runtime wifi configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
espressif-abhikroy committed Dec 7, 2023
1 parent 82c2cf8 commit 9c041c4
Show file tree
Hide file tree
Showing 13 changed files with 482 additions and 0 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/console_cmd_wifi__build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: "console_cmd_wifi: build-tests"

on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]

jobs:
build_console_cmd_wifi:
if: contains(github.event.pull_request.labels.*.name, 'console') || github.event_name == 'push'
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_target: ["esp32"]
test: [ { app: example, path: "components/console_cmd_wifi/examples" }]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
shell: bash
working-directory: ${{matrix.test.path}}
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
1 change: 1 addition & 0 deletions .github/workflows/publish-docs-component.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,6 @@ jobs:
components/console_simple_init;
components/console_cmd_ping;
components/console_cmd_ifconfig;
components/console_cmd_wifi;
namespace: "espressif"
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
8 changes: 8 additions & 0 deletions components/console_cmd_wifi/.cz.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
commitizen:
bump_message: 'bump(console): $current_version -> $new_version'
pre_bump_hooks: python ../../ci/changelog.py console_cmd_wifi
tag_format: console_cmd_wifi-v$version
version: 0.0.9
version_files:
- idf_component.yml
4 changes: 4 additions & 0 deletions components/console_cmd_wifi/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
idf_component_register(SRCS "console_wifi.c"
INCLUDE_DIRS "."
PRIV_REQUIRES esp_netif console esp_wifi
WHOLE_ARCHIVE)
51 changes: 51 additions & 0 deletions components/console_cmd_wifi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Console command wifi
The component offers a console with a command that enables runtime wifi configuration for any example project.

## API

### Steps to enable console in an example code:
1. Add this component to your project using ```idf.py add-dependency``` command.
2. In the main file of the example, add the following line:
```c
#include "console_wifi.h"
```
3. Ensure esp-netif and NVS flash is initialized and default event loop is created in your app_main():
```c
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_err_t ret = nvs_flash_init(); //Initialize NVS
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
```
4. In your app_main() function, add the following line as the last line:
```c
ESP_ERROR_CHECK(console_cmd_init()); // Initialize console

// Register all plugin command added to your project
ESP_ERROR_CHECK(console_cmd_all_register());

// To register only wifi command skip calling console_cmd_all_register()
ESP_ERROR_CHECK(console_cmd_wifi_register());

ESP_ERROR_CHECK(console_cmd_start()); // Start console
```

### Adding a plugin command or component:
To add a plugin command or any component from IDF component manager into your project, simply include an entry within the `idf_component.yml` file.

For more details refer [IDF Component Manager](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html)


## Suported command:

### wifi:
```
wifi help: Prints the help text for all wifi commands
wifi show network/sta: Scans and displays all available wifi APs./ Shows the details of wifi station.
wifi sta join <network ssid> <password>: Station joins the given wifi network.
wifi sta join <network ssid>: Station joins the given unsecured wifi network.
wifi sta leave: Station leaves the wifi network.
```
289 changes: 289 additions & 0 deletions components/console_cmd_wifi/console_wifi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_netif.h"
#include "esp_console.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_netif_net_stack.h"
#include "lwip/ip6.h"
#include "lwip/opt.h"
#include "esp_wifi.h"
#include "console_wifi.h"


#define DEFAULT_SCAN_LIST_SIZE 10

/**
* Static registration of this plugin is achieved by defining the plugin description
* structure and placing it into .console_cmd_desc section.
* The name of the section and its placement is determined by linker.lf file in 'plugins' component.
*/
static const console_cmd_plugin_desc_t __attribute__((section(".console_cmd_desc"), used)) PLUGIN = {
.name = "console_cmd_wifi",
.plugin_regd_fn = &console_cmd_wifi_register
};

typedef struct wifi_op_t {
char *name;
esp_err_t (*operation)(struct wifi_op_t *self, int argc, char *argv[]);
int arg_cnt;
int start_index;
char *help;
} wifi_op_t;

static esp_err_t wifi_help_op(wifi_op_t *self, int argc, char *argv[]);
static esp_err_t wifi_show_op(wifi_op_t *self, int argc, char *argv[]);
static esp_err_t wifi_sta_join_op(wifi_op_t *self, int argc, char *argv[]);
static esp_err_t wifi_sta_leave_op(wifi_op_t *self, int argc, char *argv[]);
//static esp_err_t wifi_sta_stop_op(wifi_op_t *self, int argc, char *argv[]);
//static esp_err_t wifi_ap_op(wifi_op_t *self, int argc, char *argv[]);

static const char *TAG = "console_wifi";

#define JOIN_TIMEOUT_MS (10000)

static EventGroupHandle_t wifi_event_group;
static const int STA_STARTED_BIT = BIT0;
static const int CONNECTED_BIT = BIT1;

static wifi_op_t cmd_list[] = {
{.name = "help", .operation = wifi_help_op, .arg_cnt = 2, .start_index = 1, .help = "wifi help: Prints the help text for all wifi commands"},
{.name = "show", .operation = wifi_show_op, .arg_cnt = 3, .start_index = 1, .help = "wifi show network/sta: Scans and displays all available wifi APs./ Shows the details of wifi station."},
{.name = "join", .operation = wifi_sta_join_op, .arg_cnt = 4, .start_index = 2, .help = "wifi sta join <network ssid> <password>: Station joins the given wifi network."},
{.name = "join", .operation = wifi_sta_join_op, .arg_cnt = 5, .start_index = 2, .help = "wifi sta join <network ssid>: Station joins the given unsecured wifi network."},
{.name = "leave", .operation = wifi_sta_leave_op, .arg_cnt = 3, .start_index = 2, .help = "wifi sta leave: Station leaves the wifi network."},
// {.name = "stop", .operation = wifi_sta_stop_op, .arg_cnt = 1, .start_index = 1, .help = "wifi"},
};

static void event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
xEventGroupSetBits(wifi_event_group, STA_STARTED_BIT);
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
}
}

static esp_err_t wifi_help_op(wifi_op_t *self, int argc, char *argv[])
{
int cmd_count = sizeof(cmd_list) / sizeof(cmd_list[0]);

for (int i = 0; i < cmd_count; i++) {
if ((cmd_list[i].help != NULL) && (strlen(cmd_list[i].help) != 0)) {
printf(" %s\n", cmd_list[i].help);
}
}

return ESP_OK;
}

uint8_t wifi_connection_status = 0;

void wifi_init(void)
{
static bool init_flag = false;
if (init_flag) {
return;
}
wifi_event_group = xEventGroupCreate();

esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);

wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));

ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_START, &event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));

ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));

ESP_ERROR_CHECK(esp_wifi_start());

int bits = xEventGroupWaitBits(wifi_event_group, STA_STARTED_BIT,
pdFALSE, pdTRUE, JOIN_TIMEOUT_MS / portTICK_PERIOD_MS);

if ((bits & STA_STARTED_BIT) == 0) {
ESP_LOGE(TAG, "Error: Wifi Connection timed out");
return;
}

init_flag = true;
}

/* Initialize Wi-Fi as sta and set scan method */
static void wifi_scan(void)
{
uint16_t number = DEFAULT_SCAN_LIST_SIZE;
wifi_ap_record_t ap_info[DEFAULT_SCAN_LIST_SIZE];
uint16_t ap_count = 0;

memset(ap_info, 0, sizeof(ap_info));

wifi_init();

esp_wifi_scan_start(NULL, true);
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count));

printf("\n");
ESP_LOGI(TAG, "Showing Wifi networks");
ESP_LOGI(TAG, "*********************");
for (int i = 0; i < number; i++) {
ESP_LOGI(TAG, "RSSI: %d\tChannel: %d\tSSID: %s", ap_info[i].rssi, ap_info[i].primary, ap_info[i].ssid);
}
ESP_LOGI(TAG, "Total APs scanned = %u, actual AP number ap_info holds = %u", ap_count, number);
}

static esp_err_t wifi_show_op(wifi_op_t *self, int argc, char *argv[])
{
if (!strcmp("network", argv[self->start_index + 1])) {
wifi_scan();
return ESP_OK;
}

if (!strcmp("sta", argv[self->start_index + 1])) {
{
wifi_config_t wifi_config = { 0 };

wifi_init();
ESP_ERROR_CHECK(esp_wifi_get_config(WIFI_IF_STA, &wifi_config));

printf("\n");
ESP_LOGI(TAG, "Showing Joind AP details:");
ESP_LOGI(TAG, "*************************");
ESP_LOGI(TAG, "SSID: %s", wifi_config.sta.ssid);
ESP_LOGI(TAG, "Password: %s", wifi_config.sta.password);
ESP_LOGI(TAG, "Channel: %d", wifi_config.sta.channel);
ESP_LOGI(TAG, "bssid: %02x:%02x:%02x:%02x:%02x:%02x", wifi_config.sta.bssid[0],
wifi_config.sta.bssid[1], wifi_config.sta.bssid[2], wifi_config.sta.bssid[3],
wifi_config.sta.bssid[4], wifi_config.sta.bssid[5]);
}
return ESP_OK;
}

return ESP_OK;
}

static esp_err_t wifi_sta_join_op(wifi_op_t *self, int argc, char *argv[])
{
wifi_config_t wifi_config = { 0 };

if (strcmp("sta", argv[self->start_index - 1])) {
ESP_LOGE(TAG, "Error: Invalid command\n");
ESP_LOGE(TAG, "%s\n", self->help);
return ESP_FAIL;
}

strlcpy((char *) wifi_config.sta.ssid, argv[self->start_index + 1], sizeof(wifi_config.sta.ssid));
if (self->arg_cnt == 5) {
strlcpy((char *) wifi_config.sta.password, argv[self->start_index + 2], sizeof(wifi_config.sta.password));
}

wifi_init();
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
esp_wifi_connect();

int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
pdFALSE, pdTRUE, JOIN_TIMEOUT_MS / portTICK_PERIOD_MS);

if ((bits & CONNECTED_BIT) == 0) {
ESP_LOGE(TAG, "Error: Wifi Connection timed out");
return ESP_OK;
}

return ESP_OK;
}

static esp_err_t wifi_sta_leave_op(wifi_op_t *self, int argc, char *argv[])
{
wifi_config_t wifi_config = { 0 };

if (strcmp("sta", argv[self->start_index - 1])) {
ESP_LOGE(TAG, "Error: Invalid command\n");
ESP_LOGE(TAG, "%s\n", self->help);
return ESP_FAIL;
}

esp_wifi_disconnect();
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));

return ESP_OK;
}

#if 0
static esp_err_t wifi_ap_op(wifi_op_t *self, int argc, char *argv[]);
{

return ESP_OK;
}
#endif

/* handle 'wifi' command */
esp_err_t do_cmd_wifi(int argc, char **argv)
{
int cmd_count = sizeof(cmd_list) / sizeof(cmd_list[0]);
wifi_op_t cmd;

for (int i = 0; i < cmd_count; i++) {
cmd = cmd_list[i];

if (argc < cmd.start_index + 1) {
continue;
}

if (!strcmp(cmd.name, argv[cmd.start_index])) {
/* Get interface for eligible commands */
if (cmd.arg_cnt == argc) {
if (cmd.operation != NULL) {
if (cmd.operation(&cmd, argc, argv) != ESP_OK) {
ESP_LOGE(TAG, "Usage:\n%s", cmd.help);
return 0;
}
}
return ESP_OK;
}
}
}

ESP_LOGE(TAG, "Command not available");

return ESP_OK;
}

/**
* @brief Registers the wifi command.
*
* @return
* - esp_err_t
*/
esp_err_t console_cmd_wifi_register(void)
{
esp_err_t ret;
esp_console_cmd_t command = {
.command = "wifi",
.help = "Command for wifi configuration and monitoring\n For more info run 'wifi help'",
.func = &do_cmd_wifi
};

ret = esp_console_cmd_register(&command);
if (ret) {
ESP_LOGE(TAG, "Unable to register wifi");
}

return ret;
}
Loading

0 comments on commit 9c041c4

Please sign in to comment.