1 /* BLE based Provisioning Example
2
3 This example code is in the Public Domain (or CC0 licensed, at your option.)
4
5 Unless required by applicable law or agreed to in writing, this
6 software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7 CONDITIONS OF ANY KIND, either express or implied.
8 */
9
10 #include <string.h>
11 #include <freertos/FreeRTOS.h>
12 #include <freertos/task.h>
13 #include <esp_system.h>
14 #include <esp_wifi.h>
15 #include <esp_event.h>
16 #include <esp_log.h>
17 #include <nvs_flash.h>
18
19 #include <lwip/err.h>
20 #include <lwip/sys.h>
21
22 #include "app_prov.h"
23 #include "qrcode.h"
24
25 #define EXAMPLE_AP_RECONN_ATTEMPTS CONFIG_EXAMPLE_AP_RECONN_ATTEMPTS
26 #define PROV_QR_VERSION "v1"
27 #define PROV_TRANSPORT_BLE "ble"
28 #define QRCODE_BASE_URL "https://espressif.github.io/esp-jumpstart/qrcode.html"
29
30 static const char *TAG = "app";
31
32 static void start_ble_provisioning(void);
33
event_handler(void * arg,esp_event_base_t event_base,int32_t event_id,void * event_data)34 static void event_handler(void* arg, esp_event_base_t event_base,
35 int32_t event_id, void* event_data)
36 {
37 static int s_retry_num_ap_not_found = 0;
38 static int s_retry_num_ap_auth_fail = 0;
39
40 if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
41 esp_wifi_connect();
42 } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
43 wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data;
44 switch (disconnected->reason) {
45 case WIFI_REASON_AUTH_EXPIRE:
46 case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT:
47 case WIFI_REASON_BEACON_TIMEOUT:
48 case WIFI_REASON_AUTH_FAIL:
49 case WIFI_REASON_ASSOC_FAIL:
50 case WIFI_REASON_HANDSHAKE_TIMEOUT:
51 ESP_LOGW(TAG, "connect to the AP fail : auth Error");
52 if (s_retry_num_ap_auth_fail < EXAMPLE_AP_RECONN_ATTEMPTS) {
53 s_retry_num_ap_auth_fail++;
54 esp_wifi_connect();
55 ESP_LOGI(TAG, "retry connecting to the AP...");
56 } else {
57 /* Restart provisioning if authentication fails */
58 start_ble_provisioning();
59 }
60 break;
61 case WIFI_REASON_NO_AP_FOUND:
62 ESP_LOGW(TAG, "connect to the AP fail : not found");
63 if (s_retry_num_ap_not_found < EXAMPLE_AP_RECONN_ATTEMPTS) {
64 s_retry_num_ap_not_found++;
65 esp_wifi_connect();
66 ESP_LOGI(TAG, "retry to connecting to the AP...");
67 }
68 break;
69 default:
70 /* None of the expected reasons */
71 esp_wifi_connect();
72 break;
73 }
74 } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
75 ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
76 ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
77 s_retry_num_ap_not_found = 0;
78 s_retry_num_ap_auth_fail = 0;
79 }
80 }
81
wifi_init_sta(void)82 static void wifi_init_sta(void)
83 {
84 /* Set our event handling */
85 ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL));
86 ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handler, NULL));
87
88 /* Start Wi-Fi in station mode with credentials set during provisioning */
89 ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
90 ESP_ERROR_CHECK(esp_wifi_start());
91 }
92
start_ble_provisioning(void)93 static void start_ble_provisioning(void)
94 {
95 /* Security version */
96 int security = 0;
97 /* Proof of possession */
98 const protocomm_security_pop_t *pop = NULL;
99
100 #ifdef CONFIG_EXAMPLE_USE_SEC_1
101 security = 1;
102 #endif
103
104 /* Having proof of possession is optional */
105 #ifdef CONFIG_EXAMPLE_USE_POP
106 const static protocomm_security_pop_t app_pop = {
107 .data = (uint8_t *) CONFIG_EXAMPLE_POP,
108 .len = (sizeof(CONFIG_EXAMPLE_POP)-1)
109 };
110 pop = &app_pop;
111 #endif
112
113 ESP_ERROR_CHECK(app_prov_start_ble_provisioning(security, pop));
114 }
115
get_device_service_name(char * service_name,size_t max)116 static void get_device_service_name(char *service_name, size_t max)
117 {
118 uint8_t eth_mac[6];
119 const char *ssid_prefix = "PROV_";
120 esp_wifi_get_mac(WIFI_IF_STA, eth_mac);
121 snprintf(service_name, max, "%s%02X%02X%02X",
122 ssid_prefix, eth_mac[3], eth_mac[4], eth_mac[5]);
123 }
124
ble_prov_print_qr(void)125 static void ble_prov_print_qr(void)
126 {
127 char payload[150] = {0};
128 char name[12] = {0};
129 char *pop = NULL;
130 #ifdef CONFIG_EXAMPLE_USE_POP
131 pop = CONFIG_EXAMPLE_POP;
132 #endif
133 get_device_service_name(name, sizeof(name));
134 if (pop) {
135 snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
136 ",\"pop\":\"%s\",\"transport\":\"%s\"}",
137 PROV_QR_VERSION, name, pop, PROV_TRANSPORT_BLE);
138 } else {
139 snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
140 ",\"transport\":\"%s\"}",
141 PROV_QR_VERSION, name, PROV_TRANSPORT_BLE);
142 }
143 #ifdef CONFIG_EXAMPLE_PROV_SHOW_QR
144 ESP_LOGI(TAG, "Scan this QR code from the provisioning application for Provisioning.");
145 esp_qrcode_config_t cfg = ESP_QRCODE_CONFIG_DEFAULT();
146 esp_qrcode_generate(&cfg, payload);
147 #endif /* CONFIG_APP_WIFI_PROV_SHOW_QR */
148 ESP_LOGI(TAG, "If QR code is not visible, copy paste the below URL in a browser.\n%s?data=%s", QRCODE_BASE_URL, payload);
149 }
150
app_main(void)151 void app_main(void)
152 {
153 /* Initialize networking stack */
154 ESP_ERROR_CHECK(esp_netif_init());
155
156 /* Create default event loop needed by the
157 * main app and the provisioning service */
158 ESP_ERROR_CHECK(esp_event_loop_create_default());
159
160 /* Initialize NVS needed by Wi-Fi */
161 ESP_ERROR_CHECK(nvs_flash_init());
162
163 /* Initialize Wi-Fi including netif with default config */
164 esp_netif_create_default_wifi_sta();
165 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
166 ESP_ERROR_CHECK(esp_wifi_init(&cfg));
167
168 /* Check if device is provisioned */
169 bool provisioned;
170 if (app_prov_is_provisioned(&provisioned) != ESP_OK) {
171 ESP_LOGE(TAG, "Error getting device provisioning state");
172 return;
173 }
174
175 if (provisioned == false) {
176 /* If not provisioned, start provisioning via BLE */
177 ESP_LOGI(TAG, "Starting BLE provisioning");
178 start_ble_provisioning();
179 ble_prov_print_qr();
180 } else {
181 /* Else start as station with credentials set during provisioning */
182 ESP_LOGI(TAG, "Starting WiFi station");
183 wifi_init_sta();
184 }
185 }
186