Closed dnlmsr closed 1 month ago
@dnlmsr do not call esp_mesh_set_type(MESH_LEAF)
can solve your problem.
@dnlmsr do not call
esp_mesh_set_type(MESH_LEAF)
can solve your problem.
This will not solve my implementation. I will try to rephrase:
In my application I want the device to always start as leaf node, thus if a mesh is already present, it will successfully connect to that mesh. However, when the device does not connect to an existing mesh, I want the device to become a root node, either via a delay or by a user action.
In the sample code I attached the 15/30s delay before calling the esp_mesh_set_type(MESH_ROOT)
is just a "simulation" of an external command calling this function.
@dnlmsr
what about the channel? When I setting the cfg.channel = 0
, it can also connects to the root node.
Answers checklist.
IDF version.
v5.2.2
Espressif SoC revision.
ESP32-D0WDQ6 (revision v1.0)
Operating System used.
Linux
How did you build your project?
Command line with idf.py
If you are using Windows, please specify command line type.
None
Development Kit.
https://www.az-delivery.de/it/products/esp32-developmentboard
Power Supply used.
USB
What is the expected behavior?
Conditions:
fixed_root
set to trueWhen designated node runs esp_mesh_set_type(MESH_ROOT) all the intermediate nodes should connect to the new fixed root node of the mesh
What is the actual behavior?
Intermediate node does not connect to the new fixed root node
Steps to reproduce.
mesh/internal_communication
Build and flash the firmware for the intermediate node with the code in
mesh_main.c
slightly changed as follows:/***
/***
define RX_SIZE (1500)
define TX_SIZE (1460)
/***
mesh_light_ctl_t light_on = { .cmd = MESH_CONTROL_CMD, .on = 1, .token_id = MESH_TOKEN_ID, .token_value = MESH_TOKEN_VALUE, };
mesh_light_ctl_t light_off = { .cmd = MESH_CONTROL_CMD, .on = 0, .token_id = MESH_TOKEN_ID, .token_value = MESH_TOKEN_VALUE, };
/***
/***
Function Definitions ***/ void esp_mesh_p2p_tx_main(void *arg) { int i; esp_err_t err; int send_count = 0; mesh_addr_t route_table[CONFIG_MESH_ROUTE_TABLE_SIZE]; int route_table_size = 0; mesh_data_t data; data.data = tx_buf; data.size = sizeof(tx_buf); data.proto = MESH_PROTO_BIN; data.tos = MESH_TOS_P2P; is_running = true;
while (is_running) { / non-root do nothing but print / if (!esp_mesh_is_root()) { ESP_LOGI(MESH_TAG, "layer:%d, rtableSize:%d, %s", mesh_layer, esp_mesh_get_routing_table_size(), (is_mesh_connected && esp_mesh_is_root()) ? "ROOT" : is_mesh_connected ? "NODE" : "DISCONNECT"); vTaskDelay(10 1000 / portTICK_PERIOD_MS); continue; } esp_mesh_get_routing_table((mesh_addr_t )&route_table, CONFIG_MESH_ROUTE_TABLE_SIZE 6, &route_table_size); if (send_count && !(send_count % 100)) { ESP_LOGI(MESH_TAG, "size:%d/%d,send_count:%d", route_table_size, esp_mesh_get_routing_table_size(), send_count); } send_count++; tx_buf[25] = (send_count >> 24) & 0xff; tx_buf[24] = (send_count >> 16) & 0xff; tx_buf[23] = (send_count >> 8) & 0xff; tx_buf[22] = (send_count >> 0) & 0xff; if (send_count % 2) { memcpy(tx_buf, (uint8_t )&light_on, sizeof(light_on)); } else { memcpy(tx_buf, (uint8_t *)&light_off, sizeof(light_off)); }
for (i = 0; i < route_table_size; i++) { err = esp_mesh_send(&route_table[i], &data, MESH_DATA_P2P, NULL, 0); if (err) { ESP_LOGE(MESH_TAG, "[ROOT-2-UNICAST:%d][L:%d]parent:" MACSTR " to " MACSTR ", heap:%" PRId32 "[err:0x%x, proto:%d, tos:%d]", send_count, mesh_layer, MAC2STR(mesh_parent_addr.addr), MAC2STR(route_table[i].addr), esp_get_minimum_free_heap_size(), err, data.proto, data.tos); } else if (!(send_count % 100)) { ESP_LOGW(MESH_TAG, "[ROOT-2-UNICAST:%d][L:%d][rtableSize:%d]parent:" MACSTR " to " MACSTR ", heap:%" PRId32 "[err:0x%x, proto:%d, tos:%d]", send_count, mesh_layer, esp_mesh_get_routing_table_size(), MAC2STR(mesh_parent_addr.addr), MAC2STR(route_table[i].addr), esp_get_minimum_free_heap_size(), err, data.proto, data.tos); } } /* if route_table_size is less than 10, add delay to avoid watchdog in this
void esp_mesh_p2p_rx_main(void *arg) { int recv_count = 0; esp_err_t err; mesh_addr_t from; int send_count = 0; mesh_data_t data; int flag = 0; data.data = rx_buf; data.size = RX_SIZE; is_running = true;
while (is_running) { data.size = RX_SIZE; err = esp_mesh_recv(&from, &data, portMAX_DELAY, &flag, NULL, 0); if (err != ESP_OK || !data.size) { ESP_LOGE(MESH_TAG, "err:0x%x, size:%d", err, data.size); continue; } / extract send count / if (data.size >= sizeof(send_count)) { send_count = (data.data[25] << 24) | (data.data[24] << 16) | (data.data[23] << 8) | data.data[22]; } recv_count++; / process light control / mesh_light_process(&from, data.data, data.size); if (!(recv_count % 1)) { ESP_LOGW( MESH_TAG, "[#RX:%d/%d][L:%d] parent:" MACSTR ", receive from " MACSTR ", size:%d, heap:%" PRId32 ", flag:%d[err:0x%x, proto:%d, tos:%d]", recv_count, send_count, mesh_layer, MAC2STR(mesh_parent_addr.addr), MAC2STR(from.addr), data.size, esp_get_minimum_free_heap_size(), flag, err, data.proto, data.tos); } } vTaskDelete(NULL); }
esp_err_t esp_mesh_comm_p2p_start(void) { static bool is_comm_p2p_started = false; if (!is_comm_p2p_started) { is_comm_p2p_started = true; xTaskCreate(esp_mesh_p2p_tx_main, "MPTX", 3072, NULL, 5, NULL); xTaskCreate(esp_mesh_p2p_rx_main, "MPRX", 3072, NULL, 5, NULL); } return ESP_OK; }
void mesh_event_handler(void arg, esp_event_base_t event_base, int32_t event_id, void event_data) { mesh_addr_t id = { 0, }; static uint16_t last_layer = 0;
switch (event_id) { case MESH_EVENT_STARTED: { esp_mesh_get_id(&id); ESP_LOGI(MESH_TAG, "ID:" MACSTR "",
MAC2STR(id.addr));
is_mesh_connected = false;
mesh_layer = esp_mesh_get_layer();
} break;
case MESH_EVENT_STOPPED: {
ESP_LOGI(MESH_TAG, "");
is_mesh_connected = false;
mesh_layer = esp_mesh_get_layer();
} break;
case MESH_EVENT_CHILD_CONNECTED: {
mesh_event_child_connected_t child_connected =
(mesh_event_child_connected_t )event_data;
ESP_LOGI(MESH_TAG, "aid:%d, " MACSTR "",
child_connected->aid, MAC2STR(child_connected->mac));
} break;
case MESH_EVENT_CHILD_DISCONNECTED: {
mesh_event_child_disconnected_t child_disconnected =
(mesh_event_child_disconnected_t )event_data;
ESP_LOGI(MESH_TAG, "aid:%d, " MACSTR "",
child_disconnected->aid, MAC2STR(child_disconnected->mac));
} break;
case MESH_EVENT_ROUTING_TABLE_ADD: {
mesh_event_routing_table_change_t routing_table =
(mesh_event_routing_table_change_t )event_data;
ESP_LOGW(MESH_TAG, "add %d, new:%d, layer:%d",
routing_table->rt_size_change, routing_table->rt_size_new,
mesh_layer);
} break;
case MESH_EVENT_ROUTING_TABLE_REMOVE: {
mesh_event_routing_table_change_t routing_table =
(mesh_event_routing_table_change_t )event_data;
ESP_LOGW(MESH_TAG,
"remove %d, new:%d, layer:%d",
routing_table->rt_size_change, routing_table->rt_size_new,
mesh_layer);
} break;
case MESH_EVENT_NO_PARENT_FOUND: {
mesh_event_no_parent_found_t no_parent =
(mesh_event_no_parent_found_t )event_data;
ESP_LOGI(MESH_TAG, "scan times:%d",
no_parent->scan_times);
}
/ TODO handler for the failure /
break;
case MESH_EVENT_PARENT_CONNECTED: {
mesh_event_connected_t connected = (mesh_event_connected_t )event_data;
esp_mesh_get_id(&id);
mesh_layer = connected->self_layer;
memcpy(&mesh_parent_addr.addr, connected->connected.bssid, 6);
ESP_LOGI(MESH_TAG,
"layer:%d-->%d, parent:" MACSTR
"%s, ID:" MACSTR ", duty:%d",
last_layer, mesh_layer, MAC2STR(mesh_parent_addr.addr),
esp_mesh_is_root() ? ""
: (mesh_layer == 2) ? ""
: "",
MAC2STR(id.addr), connected->duty);
last_layer = mesh_layer;
mesh_connected_indicator(mesh_layer);
is_mesh_connected = true;
if (esp_mesh_is_root()) {
esp_netif_dhcpc_stop(netif_sta);
esp_netif_dhcpc_start(netif_sta);
}
esp_mesh_comm_p2p_start();
} break;
case MESH_EVENT_PARENT_DISCONNECTED: {
mesh_event_disconnected_t disconnected =
(mesh_event_disconnected_t )event_data;
ESP_LOGI(MESH_TAG, "reason:%d",
disconnected->reason);
is_mesh_connected = false;
mesh_disconnected_indicator();
mesh_layer = esp_mesh_get_layer();
} break;
case MESH_EVENT_LAYER_CHANGE: {
mesh_event_layer_change_t layer_change =
(mesh_event_layer_change_t )event_data;
mesh_layer = layer_change->new_layer;
ESP_LOGI(MESH_TAG, "layer:%d-->%d%s", last_layer,
mesh_layer,
esp_mesh_is_root() ? ""
: (mesh_layer == 2) ? ""
: "");
last_layer = mesh_layer;
mesh_connected_indicator(mesh_layer);
} break;
case MESH_EVENT_ROOT_ADDRESS: {
mesh_event_root_address_t root_addr =
(mesh_event_root_address_t )event_data;
ESP_LOGI(MESH_TAG, "root address:" MACSTR "",
MAC2STR(root_addr->addr));
} break;
case MESH_EVENT_VOTE_STARTED: {
mesh_event_vote_started_t vote_started =
(mesh_event_vote_started_t )event_data;
ESP_LOGI(MESH_TAG,
"attempts:%d, reason:%d, rc_addr:" MACSTR
"",
vote_started->attempts, vote_started->reason,
MAC2STR(vote_started->rc_addr.addr));
} break;
case MESH_EVENT_VOTE_STOPPED: {
ESP_LOGI(MESH_TAG, "");
break;
}
case MESH_EVENT_ROOT_SWITCH_REQ: {
mesh_event_root_switch_req_t switch_req =
(mesh_event_root_switch_req_t )event_data;
ESP_LOGI(MESH_TAG,
"reason:%d, rc_addr:" MACSTR "",
switch_req->reason, MAC2STR(switch_req->rc_addr.addr));
} break;
case MESH_EVENT_ROOT_SWITCH_ACK: {
/ new root /
mesh_layer = esp_mesh_get_layer();
esp_mesh_get_parent_bssid(&mesh_parent_addr);
ESP_LOGI(MESH_TAG,
"layer:%d, parent:" MACSTR "",
mesh_layer, MAC2STR(mesh_parent_addr.addr));
} break;
case MESH_EVENT_TODS_STATE: {
mesh_event_toDS_state_t toDs_state = (mesh_event_toDS_state_t )event_data;
ESP_LOGI(MESH_TAG, "state:%d", toDs_state);
} break;
case MESH_EVENT_ROOT_FIXED: {
mesh_event_root_fixed_t root_fixed = (mesh_event_root_fixed_t )event_data;
ESP_LOGI(MESH_TAG, "%s",
root_fixed->is_fixed ? "fixed" : "not fixed");
} break;
case MESH_EVENT_ROOT_ASKED_YIELD: {
mesh_event_root_conflict_t root_conflict =
(mesh_event_root_conflict_t )event_data;
ESP_LOGI(MESH_TAG,
"" MACSTR ", rssi:%d, capacity:%d",
MAC2STR(root_conflict->addr), root_conflict->rssi,
root_conflict->capacity);
} break;
case MESH_EVENT_CHANNEL_SWITCH: {
mesh_event_channel_switch_t channel_switch =
(mesh_event_channel_switch_t )event_data;
ESP_LOGI(MESH_TAG, "new channel:%d",
channel_switch->channel);
} break;
case MESH_EVENT_SCAN_DONE: {
mesh_event_scan_done_t scan_done = (mesh_event_scan_done_t )event_data;
ESP_LOGI(MESH_TAG, "number:%d", scan_done->number);
} break;
case MESH_EVENT_NETWORK_STATE: {
mesh_event_network_state_t network_state =
(mesh_event_network_state_t )event_data;
ESP_LOGI(MESH_TAG, "is_rootless:%d",
network_state->is_rootless);
} break;
case MESH_EVENT_STOP_RECONNECTION: {
ESP_LOGI(MESH_TAG, "");
} break;
case MESH_EVENT_FIND_NETWORK: {
mesh_event_find_network_t find_network =
(mesh_event_find_network_t )event_data;
ESP_LOGI(MESH_TAG,
"new channel:%d, router BSSID:" MACSTR "",
find_network->channel, MAC2STR(find_network->router_bssid));
} break;
case MESH_EVENT_ROUTER_SWITCH: {
mesh_event_router_switch_t router_switch =
(mesh_event_router_switch_t )event_data;
ESP_LOGI(MESH_TAG,
"new router:%s, channel:%d, " MACSTR "",
router_switch->ssid, router_switch->channel,
MAC2STR(router_switch->bssid));
} break;
case MESH_EVENT_PS_PARENT_DUTY: {
mesh_event_ps_duty_t ps_duty = (mesh_event_ps_duty_t )event_data;
ESP_LOGI(MESH_TAG, "duty:%d", ps_duty->duty);
} break;
case MESH_EVENT_PS_CHILD_DUTY: {
mesh_event_ps_duty_t ps_duty = (mesh_event_ps_duty_t *)event_data;
ESP_LOGI(MESH_TAG, "cidx:%d, " MACSTR ", duty:%d",
ps_duty->child_connected.aid - 1,
MAC2STR(ps_duty->child_connected.mac), ps_duty->duty);
} break;
default:
ESP_LOGI(MESH_TAG, "unknown id:%" PRId32 "", event_id);
break;
}
}
void ip_event_handler(void arg, esp_event_base_t event_base, int32_t event_id, void event_data) { ip_event_got_ip_t event = (ip_event_got_ip_t )event_data; ESP_LOGI(MESH_TAG, "IP:" IPSTR,
IP2STR(&event->ip_info.ip));
}
void app_main(void) { ESP_ERROR_CHECK(mesh_light_init()); ESP_ERROR_CHECK(nvs_flash_init()); / tcpip initialization / ESP_ERROR_CHECK(esp_netif_init()); / event initialization / ESP_ERROR_CHECK(esp_event_loop_create_default()); /* create network interfaces for mesh (only station instance saved for
ifdef CONFIG_MESH_ENABLE_PS
/ Enable mesh PS function / ESP_ERROR_CHECK(esp_mesh_enable_ps()); /* better to increase the associate expired time, if a small duty cycle is
else
/ Disable mesh PS function / ESP_ERROR_CHECK(esp_mesh_disable_ps()); ESP_ERROR_CHECK(esp_mesh_set_ap_assoc_expire(10));
endif
mesh_cfg_t cfg = MESH_INIT_CONFIG_DEFAULT(); / mesh ID / memcpy((uint8_t )&cfg.mesh_id, MESH_ID, 6); / router / cfg.channel = 1; cfg.router.ssid_len = strlen(CONFIG_MESH_ROUTER_SSID); memcpy((uint8_t )&cfg.router.ssid, CONFIG_MESH_ROUTER_SSID, cfg.router.ssid_len); memcpy((uint8_t )&cfg.router.password, CONFIG_MESH_ROUTER_PASSWD, strlen(CONFIG_MESH_ROUTER_PASSWD)); / mesh softAP / ESP_ERROR_CHECK(esp_mesh_set_ap_authmode(CONFIG_MESH_AP_AUTHMODE)); cfg.mesh_ap.max_connection = CONFIG_MESH_AP_CONNECTIONS; cfg.mesh_ap.nonmesh_max_connection = CONFIG_MESH_NON_MESH_AP_CONNECTIONS; memcpy((uint8_t )&cfg.mesh_ap.password, CONFIG_MESH_AP_PASSWD, strlen(CONFIG_MESH_AP_PASSWD)); ESP_ERROR_CHECK(esp_mesh_set_config(&cfg)); / mesh start / ESP_ERROR_CHECK(esp_mesh_start()); ESP_ERROR_CHECK(esp_mesh_fix_root(true));
ifdef CONFIG_MESH_ENABLE_PS
/ set the device active duty cycle. (default:10, MESH_PS_DEVICE_DUTY_REQUEST) / ESP_ERROR_CHECK(esp_mesh_set_active_duty_cycle(CONFIG_MESH_PS_DEV_DUTY, CONFIG_MESH_PS_DEV_DUTY_TYPE)); /* set the network active duty cycle. (default:10, -1,
endif
ESP_LOGI( MESH_TAG, "mesh starts successfully, heap:%" PRId32 ", %s<%d>%s, ps:%d", esp_get_minimum_free_heap_size(), esp_mesh_is_root_fixed() ? "root fixed" : "root not fixed", esp_mesh_get_topology(), esp_mesh_get_topology() ? "(chain)" : "(tree)", esp_mesh_is_ps_enabled()); }
Build and flash the firmware for the designated root node with the following code in
mesh_main.c
(node starts as MESH_LEAF, then after 30s turns to MESH_ROOT):/***
/***
define RX_SIZE (1500)
define TX_SIZE (1460)
/***
mesh_light_ctl_t light_on = { .cmd = MESH_CONTROL_CMD, .on = 1, .token_id = MESH_TOKEN_ID, .token_value = MESH_TOKEN_VALUE, };
mesh_light_ctl_t light_off = { .cmd = MESH_CONTROL_CMD, .on = 0, .token_id = MESH_TOKEN_ID, .token_value = MESH_TOKEN_VALUE, };
/***
/***
Function Definitions ***/ void esp_mesh_p2p_tx_main(void *arg) { int i; esp_err_t err; int send_count = 0; mesh_addr_t route_table[CONFIG_MESH_ROUTE_TABLE_SIZE]; int route_table_size = 0; mesh_data_t data; data.data = tx_buf; data.size = sizeof(tx_buf); data.proto = MESH_PROTO_BIN; data.tos = MESH_TOS_P2P; is_running = true;
while (is_running) { / non-root do nothing but print / if (!esp_mesh_is_root()) { ESP_LOGI(MESH_TAG, "layer:%d, rtableSize:%d, %s", mesh_layer, esp_mesh_get_routing_table_size(), (is_mesh_connected && esp_mesh_is_root()) ? "ROOT" : is_mesh_connected ? "NODE" : "DISCONNECT"); vTaskDelay(10 1000 / portTICK_PERIOD_MS); continue; } esp_mesh_get_routing_table((mesh_addr_t )&route_table, CONFIG_MESH_ROUTE_TABLE_SIZE 6, &route_table_size); if (send_count && !(send_count % 100)) { ESP_LOGI(MESH_TAG, "size:%d/%d,send_count:%d", route_table_size, esp_mesh_get_routing_table_size(), send_count); } send_count++; tx_buf[25] = (send_count >> 24) & 0xff; tx_buf[24] = (send_count >> 16) & 0xff; tx_buf[23] = (send_count >> 8) & 0xff; tx_buf[22] = (send_count >> 0) & 0xff; if (send_count % 2) { memcpy(tx_buf, (uint8_t )&light_on, sizeof(light_on)); } else { memcpy(tx_buf, (uint8_t *)&light_off, sizeof(light_off)); }
for (i = 0; i < route_table_size; i++) { err = esp_mesh_send(&route_table[i], &data, MESH_DATA_P2P, NULL, 0); if (err) { ESP_LOGE(MESH_TAG, "[ROOT-2-UNICAST:%d][L:%d]parent:" MACSTR " to " MACSTR ", heap:%" PRId32 "[err:0x%x, proto:%d, tos:%d]", send_count, mesh_layer, MAC2STR(mesh_parent_addr.addr), MAC2STR(route_table[i].addr), esp_get_minimum_free_heap_size(), err, data.proto, data.tos); } else if (!(send_count % 100)) { ESP_LOGW(MESH_TAG, "[ROOT-2-UNICAST:%d][L:%d][rtableSize:%d]parent:" MACSTR " to " MACSTR ", heap:%" PRId32 "[err:0x%x, proto:%d, tos:%d]", send_count, mesh_layer, esp_mesh_get_routing_table_size(), MAC2STR(mesh_parent_addr.addr), MAC2STR(route_table[i].addr), esp_get_minimum_free_heap_size(), err, data.proto, data.tos); } } /* if route_table_size is less than 10, add delay to avoid watchdog in this
void esp_mesh_p2p_rx_main(void *arg) { int recv_count = 0; esp_err_t err; mesh_addr_t from; int send_count = 0; mesh_data_t data; int flag = 0; data.data = rx_buf; data.size = RX_SIZE; is_running = true;
while (is_running) { data.size = RX_SIZE; err = esp_mesh_recv(&from, &data, portMAX_DELAY, &flag, NULL, 0); if (err != ESP_OK || !data.size) { ESP_LOGE(MESH_TAG, "err:0x%x, size:%d", err, data.size); continue; } / extract send count / if (data.size >= sizeof(send_count)) { send_count = (data.data[25] << 24) | (data.data[24] << 16) | (data.data[23] << 8) | data.data[22]; } recv_count++; / process light control / mesh_light_process(&from, data.data, data.size); if (!(recv_count % 1)) { ESP_LOGW( MESH_TAG, "[#RX:%d/%d][L:%d] parent:" MACSTR ", receive from " MACSTR ", size:%d, heap:%" PRId32 ", flag:%d[err:0x%x, proto:%d, tos:%d]", recv_count, send_count, mesh_layer, MAC2STR(mesh_parent_addr.addr), MAC2STR(from.addr), data.size, esp_get_minimum_free_heap_size(), flag, err, data.proto, data.tos); } } vTaskDelete(NULL); }
esp_err_t esp_mesh_comm_p2p_start(void) { static bool is_comm_p2p_started = false; if (!is_comm_p2p_started) { is_comm_p2p_started = true; xTaskCreate(esp_mesh_p2p_tx_main, "MPTX", 3072, NULL, 5, NULL); xTaskCreate(esp_mesh_p2p_rx_main, "MPRX", 3072, NULL, 5, NULL); } return ESP_OK; }
void mesh_event_handler(void arg, esp_event_base_t event_base, int32_t event_id, void event_data) { mesh_addr_t id = { 0, }; static uint16_t last_layer = 0;
switch (event_id) { case MESH_EVENT_STARTED: { esp_mesh_get_id(&id); ESP_LOGI(MESH_TAG, "ID:" MACSTR "",
MAC2STR(id.addr));
is_mesh_connected = false;
mesh_layer = esp_mesh_get_layer();
} break;
case MESH_EVENT_STOPPED: {
ESP_LOGI(MESH_TAG, "");
is_mesh_connected = false;
mesh_layer = esp_mesh_get_layer();
} break;
case MESH_EVENT_CHILD_CONNECTED: {
mesh_event_child_connected_t child_connected =
(mesh_event_child_connected_t )event_data;
ESP_LOGI(MESH_TAG, "aid:%d, " MACSTR "",
child_connected->aid, MAC2STR(child_connected->mac));
} break;
case MESH_EVENT_CHILD_DISCONNECTED: {
mesh_event_child_disconnected_t child_disconnected =
(mesh_event_child_disconnected_t )event_data;
ESP_LOGI(MESH_TAG, "aid:%d, " MACSTR "",
child_disconnected->aid, MAC2STR(child_disconnected->mac));
} break;
case MESH_EVENT_ROUTING_TABLE_ADD: {
mesh_event_routing_table_change_t routing_table =
(mesh_event_routing_table_change_t )event_data;
ESP_LOGW(MESH_TAG, "add %d, new:%d, layer:%d",
routing_table->rt_size_change, routing_table->rt_size_new,
mesh_layer);
} break;
case MESH_EVENT_ROUTING_TABLE_REMOVE: {
mesh_event_routing_table_change_t routing_table =
(mesh_event_routing_table_change_t )event_data;
ESP_LOGW(MESH_TAG,
"remove %d, new:%d, layer:%d",
routing_table->rt_size_change, routing_table->rt_size_new,
mesh_layer);
} break;
case MESH_EVENT_NO_PARENT_FOUND: {
mesh_event_no_parent_found_t no_parent =
(mesh_event_no_parent_found_t )event_data;
ESP_LOGI(MESH_TAG, "scan times:%d",
no_parent->scan_times);
}
/ TODO handler for the failure /
break;
case MESH_EVENT_PARENT_CONNECTED: {
mesh_event_connected_t connected = (mesh_event_connected_t )event_data;
esp_mesh_get_id(&id);
mesh_layer = connected->self_layer;
memcpy(&mesh_parent_addr.addr, connected->connected.bssid, 6);
ESP_LOGI(MESH_TAG,
"layer:%d-->%d, parent:" MACSTR
"%s, ID:" MACSTR ", duty:%d",
last_layer, mesh_layer, MAC2STR(mesh_parent_addr.addr),
esp_mesh_is_root() ? ""
: (mesh_layer == 2) ? ""
: "",
MAC2STR(id.addr), connected->duty);
last_layer = mesh_layer;
mesh_connected_indicator(mesh_layer);
is_mesh_connected = true;
if (esp_mesh_is_root()) {
esp_netif_dhcpc_stop(netif_sta);
esp_netif_dhcpc_start(netif_sta);
}
esp_mesh_comm_p2p_start();
} break;
case MESH_EVENT_PARENT_DISCONNECTED: {
mesh_event_disconnected_t disconnected =
(mesh_event_disconnected_t )event_data;
ESP_LOGI(MESH_TAG, "reason:%d",
disconnected->reason);
is_mesh_connected = false;
mesh_disconnected_indicator();
mesh_layer = esp_mesh_get_layer();
} break;
case MESH_EVENT_LAYER_CHANGE: {
mesh_event_layer_change_t layer_change =
(mesh_event_layer_change_t )event_data;
mesh_layer = layer_change->new_layer;
ESP_LOGI(MESH_TAG, "layer:%d-->%d%s", last_layer,
mesh_layer,
esp_mesh_is_root() ? ""
: (mesh_layer == 2) ? ""
: "");
last_layer = mesh_layer;
mesh_connected_indicator(mesh_layer);
} break;
case MESH_EVENT_ROOT_ADDRESS: {
mesh_event_root_address_t root_addr =
(mesh_event_root_address_t )event_data;
ESP_LOGI(MESH_TAG, "root address:" MACSTR "",
MAC2STR(root_addr->addr));
} break;
case MESH_EVENT_VOTE_STARTED: {
mesh_event_vote_started_t vote_started =
(mesh_event_vote_started_t )event_data;
ESP_LOGI(MESH_TAG,
"attempts:%d, reason:%d, rc_addr:" MACSTR
"",
vote_started->attempts, vote_started->reason,
MAC2STR(vote_started->rc_addr.addr));
} break;
case MESH_EVENT_VOTE_STOPPED: {
ESP_LOGI(MESH_TAG, "");
break;
}
case MESH_EVENT_ROOT_SWITCH_REQ: {
mesh_event_root_switch_req_t switch_req =
(mesh_event_root_switch_req_t )event_data;
ESP_LOGI(MESH_TAG,
"reason:%d, rc_addr:" MACSTR "",
switch_req->reason, MAC2STR(switch_req->rc_addr.addr));
} break;
case MESH_EVENT_ROOT_SWITCH_ACK: {
/ new root /
mesh_layer = esp_mesh_get_layer();
esp_mesh_get_parent_bssid(&mesh_parent_addr);
ESP_LOGI(MESH_TAG,
"layer:%d, parent:" MACSTR "",
mesh_layer, MAC2STR(mesh_parent_addr.addr));
} break;
case MESH_EVENT_TODS_STATE: {
mesh_event_toDS_state_t toDs_state = (mesh_event_toDS_state_t )event_data;
ESP_LOGI(MESH_TAG, "state:%d", toDs_state);
} break;
case MESH_EVENT_ROOT_FIXED: {
mesh_event_root_fixed_t root_fixed = (mesh_event_root_fixed_t )event_data;
ESP_LOGI(MESH_TAG, "%s",
root_fixed->is_fixed ? "fixed" : "not fixed");
} break;
case MESH_EVENT_ROOT_ASKED_YIELD: {
mesh_event_root_conflict_t root_conflict =
(mesh_event_root_conflict_t )event_data;
ESP_LOGI(MESH_TAG,
"" MACSTR ", rssi:%d, capacity:%d",
MAC2STR(root_conflict->addr), root_conflict->rssi,
root_conflict->capacity);
} break;
case MESH_EVENT_CHANNEL_SWITCH: {
mesh_event_channel_switch_t channel_switch =
(mesh_event_channel_switch_t )event_data;
ESP_LOGI(MESH_TAG, "new channel:%d",
channel_switch->channel);
} break;
case MESH_EVENT_SCAN_DONE: {
mesh_event_scan_done_t scan_done = (mesh_event_scan_done_t )event_data;
ESP_LOGI(MESH_TAG, "number:%d", scan_done->number);
} break;
case MESH_EVENT_NETWORK_STATE: {
mesh_event_network_state_t network_state =
(mesh_event_network_state_t )event_data;
ESP_LOGI(MESH_TAG, "is_rootless:%d",
network_state->is_rootless);
} break;
case MESH_EVENT_STOP_RECONNECTION: {
ESP_LOGI(MESH_TAG, "");
} break;
case MESH_EVENT_FIND_NETWORK: {
mesh_event_find_network_t find_network =
(mesh_event_find_network_t )event_data;
ESP_LOGI(MESH_TAG,
"new channel:%d, router BSSID:" MACSTR "",
find_network->channel, MAC2STR(find_network->router_bssid));
} break;
case MESH_EVENT_ROUTER_SWITCH: {
mesh_event_router_switch_t router_switch =
(mesh_event_router_switch_t )event_data;
ESP_LOGI(MESH_TAG,
"new router:%s, channel:%d, " MACSTR "",
router_switch->ssid, router_switch->channel,
MAC2STR(router_switch->bssid));
} break;
case MESH_EVENT_PS_PARENT_DUTY: {
mesh_event_ps_duty_t ps_duty = (mesh_event_ps_duty_t )event_data;
ESP_LOGI(MESH_TAG, "duty:%d", ps_duty->duty);
} break;
case MESH_EVENT_PS_CHILD_DUTY: {
mesh_event_ps_duty_t ps_duty = (mesh_event_ps_duty_t *)event_data;
ESP_LOGI(MESH_TAG, "cidx:%d, " MACSTR ", duty:%d",
ps_duty->child_connected.aid - 1,
MAC2STR(ps_duty->child_connected.mac), ps_duty->duty);
} break;
default:
ESP_LOGI(MESH_TAG, "unknown id:%" PRId32 "", event_id);
break;
}
}
void ip_event_handler(void arg, esp_event_base_t event_base, int32_t event_id, void event_data) { ip_event_got_ip_t event = (ip_event_got_ip_t )event_data; ESP_LOGI(MESH_TAG, "IP:" IPSTR,
IP2STR(&event->ip_info.ip));
}
void app_main(void) { ESP_ERROR_CHECK(mesh_light_init()); ESP_ERROR_CHECK(nvs_flash_init()); / tcpip initialization / ESP_ERROR_CHECK(esp_netif_init()); / event initialization / ESP_ERROR_CHECK(esp_event_loop_create_default()); /* create network interfaces for mesh (only station instance saved for
ifdef CONFIG_MESH_ENABLE_PS
/ Enable mesh PS function / ESP_ERROR_CHECK(esp_mesh_enable_ps()); /* better to increase the associate expired time, if a small duty cycle is
else
/ Disable mesh PS function / ESP_ERROR_CHECK(esp_mesh_disable_ps()); ESP_ERROR_CHECK(esp_mesh_set_ap_assoc_expire(10));
endif
mesh_cfg_t cfg = MESH_INIT_CONFIG_DEFAULT(); / mesh ID / memcpy((uint8_t )&cfg.mesh_id, MESH_ID, 6); / router / cfg.channel = 1; cfg.router.ssid_len = strlen(CONFIG_MESH_ROUTER_SSID); memcpy((uint8_t )&cfg.router.ssid, CONFIG_MESH_ROUTER_SSID, cfg.router.ssid_len); memcpy((uint8_t )&cfg.router.password, CONFIG_MESH_ROUTER_PASSWD, strlen(CONFIG_MESH_ROUTER_PASSWD)); / mesh softAP / ESP_ERROR_CHECK(esp_mesh_set_ap_authmode(CONFIG_MESH_AP_AUTHMODE)); cfg.mesh_ap.max_connection = CONFIG_MESH_AP_CONNECTIONS; cfg.mesh_ap.nonmesh_max_connection = CONFIG_MESH_NON_MESH_AP_CONNECTIONS; memcpy((uint8_t )&cfg.mesh_ap.password, CONFIG_MESH_AP_PASSWD, strlen(CONFIG_MESH_AP_PASSWD)); ESP_ERROR_CHECK(esp_mesh_set_config(&cfg)); / mesh start / ESP_ERROR_CHECK(esp_mesh_start()); ESP_ERROR_CHECK(esp_mesh_fix_root(true)); ESP_ERROR_CHECK(esp_mesh_set_type(MESH_LEAF));
ifdef CONFIG_MESH_ENABLE_PS
/ set the device active duty cycle. (default:10, MESH_PS_DEVICE_DUTY_REQUEST) / ESP_ERROR_CHECK(esp_mesh_set_active_duty_cycle(CONFIG_MESH_PS_DEV_DUTY, CONFIG_MESH_PS_DEV_DUTY_TYPE)); /* set the network active duty cycle. (default:10, -1,
MESH_PS_NETWORK_DUTY_APPLIED_ENTIRE) */ ESP_ERROR_CHECK(esp_mesh_set_network_duty_cycle( CONFIG_MESH_PS_NWK_DUTY, CONFIG_MESH_PS_NWK_DUTY_DURATION, CONFIG_MESH_PS_NWK_DUTY_RULE));
endif
ESP_LOGI( MESH_TAG, "mesh starts successfully, heap:%" PRId32 ", %s<%d>%s, ps:%d", esp_get_minimum_free_heap_size(), esp_mesh_is_root_fixed() ? "root fixed" : "root not fixed", esp_mesh_get_topology(), esp_mesh_get_topology() ? "(chain)" : "(tree)", esp_mesh_is_ps_enabled());
vTaskDelay(pdMS_TO_TICKS(30 * 1000)); ESP_ERROR_CHECK(esp_mesh_set_type(MESH_ROOT)); }
Debug Logs.
More Information.
Provided code is mostly equal as the already existing example. Notable changes start after
esp_mesh_start
As a result I would like to provision an "offline mesh" without a Wi-Fi router. Since we need a way to elect a fixed root in order to form the mesh, a designated node after some time automatically promotes itself to root node.
Everything works if the switch with
esp_set_mesh_type(MESH_ROOT)
happens before 15s after boot. A longer wait time will cause the following log lines:Which is why I suspect that after the switch to root node, it notifies the nodes around that the mesh does not have a root node.