arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
URLStreamESP32.h
1#pragma once
2
3#include "AudioTools/CoreAudio/AudioHttp/AbstractURLStream.h"
4#include "AudioTools/CoreAudio/AudioHttp/HttpRequest.h"
5#include "AudioTools/CoreAudio/AudioHttp/ICYStreamT.h"
6#include "AudioTools/CoreAudio/AudioHttp/URLStreamBufferedT.h"
7#include "esp_crt_bundle.h"
8#include "esp_http_client.h"
9#include "esp_idf_version.h"
10#include "esp_system.h"
11#include "esp_wifi.h"
12#include "nvs_flash.h"
13
14namespace audio_tools {
15
23class WiFiESP32 {
24 public:
25 bool begin(const char* ssid, const char* password) {
26 TRACEI();
27 if (is_open) return true;
28 if (!setupWIFI(ssid, password)) {
29 LOGE("setupWIFI failed");
30 return false;
31 }
32
33 return true;
34 }
35
36 void end() {
37 TRACED();
38 if (is_open) {
39 TRACEI();
42 }
43 is_open = false;
44 }
45
46 void setPowerSave(wifi_ps_type_t powerSave) { power_save = powerSave; }
47
48 bool isConnected() { return is_open; }
49
50 protected:
51 volatile bool is_open = false;
52 esp_ip4_addr_t ip = {0};
53 wifi_ps_type_t power_save = WIFI_PS_NONE;
54
55 bool setupWIFI(const char* ssid, const char* password) {
56 assert(ssid != nullptr);
57 assert(password != nullptr);
58 LOGI("setupWIFI: %s", ssid);
60 if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
63 ret = nvs_flash_init();
64 }
65
66 if (esp_netif_init() != ESP_OK) {
67 LOGE("esp_netif_init");
68 return false;
69 };
70
72 LOGE("esp_event_loop_create_default");
73 return false;
74 };
75
77 if (itf == nullptr) {
78 LOGE("esp_netif_create_default_wifi_sta");
79 return false;
80 };
81
83 &wifi_sta_event_handler, this, NULL);
85 &wifi_sta_event_handler, this, NULL);
87 if (esp_wifi_init(&cfg) != ESP_OK) {
88 LOGE("esp_wifi_init");
89 return false;
90 }
91
93 esp_wifi_set_ps(power_save);
94
96 memset(&sta_config, 0, sizeof(wifi_config_t));
97 strncpy((char*)sta_config.sta.ssid, ssid, 32);
98 strncpy((char*)sta_config.sta.password, password, 32);
99 sta_config.sta.threshold.authmode = WIFI_AUTH_WPA_WPA2_PSK;
101
102 // start wifi
103 bool rc = esp_wifi_start() == ESP_OK;
104 if (!rc) {
105 LOGE("esp_wifi_start");
106 }
107 return rc;
108 }
109
110 static void wifi_sta_event_handler(void* arg, esp_event_base_t event_base,
111 int32_t event_id, void* event_data) {
112 WiFiESP32* self = (WiFiESP32*)arg;
113
114 if (event_base == WIFI_EVENT) {
115 switch (event_id) {
117 LOGI("WIFI_EVENT_STA_START");
119 break;
121 LOGI("WIFI_EVENT_STA_DISCONNECTED");
123 break;
124 }
125 } else if (event_base == IP_EVENT) {
126 switch (event_id) {
127 case IP_EVENT_STA_GOT_IP: {
129 self->ip = event->ip_info.ip;
130 self->is_open = true;
131 LOGI("==> Station connected with IP: " IPSTR ", GW: " IPSTR
132 ", Mask: " IPSTR ".",
133 IP2STR(&event->ip_info.ip), IP2STR(&event->ip_info.gw),
134 IP2STR(&event->ip_info.netmask));
135 break;
136 }
137 }
138 }
139 }
140
141} static IDF_WIFI;
142
143class URLStreamESP32;
144static URLStreamESP32* actualURLStreamESP32 = nullptr;
145
165 public:
166 URLStreamESP32(const char* ssid, const char* pwd) {
167 setSSID(ssid);
169 _timeout = 8000;
170 }
171 URLStreamESP32() : URLStreamESP32(nullptr, nullptr) {}
172 ~URLStreamESP32() { end(); }
173 // executes the URL request
174 virtual bool begin(const char* urlStr, const char* acceptMime = "",
175 MethodID action = GET, const char* reqMime = "",
176 const char* reqData = "") {
177 TRACED();
178 // start wifi if necessary and possible
179 if (ssid != nullptr) {
180 if (!IDF_WIFI.begin(ssid, password)) {
181 LOGE("Wifi failed");
182 return false;
183 }
184 if (!IDF_WIFI.isConnected()) {
185 // wait for connection
186 Serial.print("Waiting for connection ");
187 while (!IDF_WIFI.isConnected()) {
188 delay(200);
189 Serial.print(".");
190 }
191 Serial.println();
192 }
193 }
194
195 // for headers
196 actualURLStreamESP32 = this;
197
198 // determine wifi country
200 memset(&cntry, 0, sizeof(wifi_country_t));
202 char text[4] = {0};
203 strncpy(text, cntry.cc, 3);
204 LOGI("wifi country: %s", text);
205
206 // fill http_config
208 memset(&http_config, 0, sizeof(http_config));
209 http_config.url = urlStr;
210 http_config.user_agent = DEFAULT_AGENT;
211 http_config.event_handler = http_event_handler;
212 http_config.buffer_size = buffer_size;
213 http_config.timeout_ms = _timeout;
214 http_config.user_data = this;
215 // for SSL certificate
216 if (pem_cert != nullptr) {
217 http_config.cert_pem = (const char*)pem_cert;
218 http_config.cert_len = pem_cert_len;
219 }
220 // for SSL (use of a bundle for certificate verification)
221 if (crt_bundle_attach != nullptr) {
222 http_config.crt_bundle_attach = crt_bundle_attach;
223 }
224
225 switch (action) {
226 case GET:
228 break;
229 case POST:
231 break;
232 case PUT:
234 break;
235 case DELETE:
237 break;
238 default:
239 LOGE("Unsupported action: %d", action);
240 break;
241 }
242
243 // Init only the first time
244 if (client_handle == nullptr) {
245 client_handle = esp_http_client_init(&http_config);
246 }
247
248 // process header parameters
249 if (!StrView(acceptMime).isEmpty()) addRequestHeader(ACCEPT, acceptMime);
250 if (!StrView(reqMime).isEmpty()) addRequestHeader(CONTENT_TYPE, reqMime);
251 List<HttpHeaderLine*>& lines = request.header().getHeaderLines();
252 for (auto it = lines.begin(); it != lines.end(); ++it) {
253 if ((*it)->active) {
254 esp_http_client_set_header(client_handle, (*it)->key.c_str(),
255 (*it)->value.c_str());
256 }
257 }
258
259 // Open http
260 if (esp_http_client_open(client_handle, 0) != ESP_OK) {
261 LOGE("esp_http_client_open");
262 return false;
263 }
264
265 // Determine the result
267 int status_code = esp_http_client_get_status_code(client_handle);
268 LOGI("status_code: %d / content_length: %d", status_code, content_length);
269
270 // Process post/put data
271 StrView data(reqData);
272 if (!data.isEmpty()) {
273 write((const uint8_t*)reqData, data.length());
274 }
275
276 return status_code == 200;
277 }
278 // ends the request
279 virtual void end() override {
280 esp_http_client_close(client_handle);
281 esp_http_client_cleanup(client_handle);
282 }
283
285 int availableForWrite() override { return 1024; }
286
288 virtual void setSSID(const char* ssid) { this->ssid = ssid; }
289
291 virtual void setPassword(const char* password) { this->password = password; }
292
294 virtual void setPowerSave(bool ps) {
295 IDF_WIFI.setPowerSave(ps ? WIFI_PS_MAX_MODEM : WIFI_PS_NONE);
296 }
297
298 size_t write(const uint8_t* data, size_t len) override {
299 TRACED();
300 return esp_http_client_write(client_handle, (const char*)data, len);
301 }
302
303 size_t readBytes(uint8_t* data, size_t len) override {
304 TRACED();
305 return esp_http_client_read(client_handle, (char*)data, len);
306 }
307
309 void addRequestHeader(const char* key, const char* value) override {
310 TRACED();
311 request.addRequestHeader(key, value);
312 }
314 const char* getReplyHeader(const char* key) override {
315 return request.getReplyHeader(key);
316 }
317
320 void setCACert(const char* cert) override {
321 int len = strlen(cert);
322 setCACert((const uint8_t*)cert, len + 1);
323 }
324
327 void setCACert(esp_err_t (*cb)(void *conf)){
328 crt_bundle_attach = cb;
329 }
330
332 void setReadBufferSize(int size) {
333 buffer_size = size; }
334
337 return request; }
338
340 void setClient(Client& client) override {}
341
342 protected:
343 int id = 0;
344 HttpRequest request;
345 esp_http_client_handle_t client_handle = nullptr;
346 bool is_power_save = false;
347 const char* ssid = nullptr;
348 const char* password = nullptr;
349 int buffer_size = DEFAULT_BUFFER_SIZE;
350 const uint8_t* pem_cert = nullptr;
351 int pem_cert_len = 0;
352 esp_err_t (*crt_bundle_attach)(void *conf) = nullptr;
353
354
357 void setCACert(const uint8_t* cert, int len) {
358 pem_cert_len = len;
359 pem_cert = cert;
360 // certificate must end with traling null
361 assert(cert[len - 1] == 0);
362 }
363
364 static esp_err_t http_event_handler(esp_http_client_event_t* evt) {
365 switch (evt->event_id) {
366 case HTTP_EVENT_ERROR:
367 LOGI("HTTP_EVENT_ERROR");
368 break;
370 LOGD("HTTP_EVENT_ON_CONNECTED");
371 break;
373 LOGD("HTTP_EVENT_HEADER_SENT");
374 break;
376 LOGI("HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key,
377 evt->header_value);
378 // store reply headers
379 actualURLStreamESP32->request.reply().put(evt->header_key,
380 evt->header_value);
381 break;
383 LOGD("HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
384 break;
386 LOGI("HTTP_EVENT_ON_FINISH");
387 break;
389 LOGI("HTTP_EVENT_DISCONNECTED");
390 break;
391#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 3, 7)
393 LOGI("HTTP_EVENT_REDIRECT");
394 break;
395#endif
396 }
397 return ESP_OK;
398 }
399};
400
405
407#if !defined(ARDUINO)
411#endif
412
413} // namespace audio_tools
Abstract Base class for all URLStream implementations.
Definition AbstractURLStream.h:17
Definition NoArduino.h:167
Simple API to process get, put, post, del http requests I tried to use Arduino HttpClient,...
Definition HttpRequest.h:25
void addRequestHeader(const char *key, const char *value)
Adds/Updates a request header.
Definition HttpRequest.h:191
virtual HttpRequestHeader & header()
provides access to the request header
Definition HttpRequest.h:160
A simple wrapper to provide string functions on existing allocated char*. If the underlying char* is ...
Definition StrView.h:28
virtual int length()
Definition StrView.h:383
virtual bool isEmpty()
checks if the string is empty
Definition StrView.h:386
URLStream using the ESP32 IDF API.
Definition URLStreamESP32.h:164
virtual void setPowerSave(bool ps)
Sets the power save mode (default false)!
Definition URLStreamESP32.h:294
void setCACert(esp_err_t(*cb)(void *conf))
Definition URLStreamESP32.h:327
virtual void setSSID(const char *ssid)
Sets the ssid that will be used for logging in (when calling begin)
Definition URLStreamESP32.h:288
virtual void setPassword(const char *password)
Sets the password that will be used for logging in (when calling begin)
Definition URLStreamESP32.h:291
HttpRequest & httpRequest() override
Used for request and reply header parameters.
Definition URLStreamESP32.h:336
void setCACert(const uint8_t *cert, int len)
Definition URLStreamESP32.h:357
int availableForWrite() override
Writes are not supported.
Definition URLStreamESP32.h:285
void addRequestHeader(const char *key, const char *value) override
Adds/Updates a request header.
Definition URLStreamESP32.h:309
void setCACert(const char *cert) override
Definition URLStreamESP32.h:320
void setClient(Client &client) override
Does nothing.
Definition URLStreamESP32.h:340
void setReadBufferSize(int size)
Defines the read buffer size.
Definition URLStreamESP32.h:332
const char * getReplyHeader(const char *key) override
Provides a header entry.
Definition URLStreamESP32.h:314
Represents the content of a URL as Stream. We use the WiFi.h API. If you run into performance issues,...
Definition URLStream.h:32
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
Login to Wifi using the ESP32 IDF functionality. This can be accessed with the global object IDF_WIFI...
Definition URLStreamESP32.h:23
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioConfig.h:885