#include #include #include "bme280.h" // Deine BME280 Sensor-Bibliothek #include "hardware/i2c.h" // Nötig für I2C-Definitionen, falls bme280.h sie nicht enthält #include "lwip/pbuf.h" #include "lwip/tcp.h" #include "pico/cyw43_arch.h" #include "pico/stdlib.h" #define TCP_PORT 80 #define DEBUG_printf printf #define BUF_SIZE 8192 * 4 // Kann angepasst werden für größere HTML/JSON #define POLL_TIME_S 5 static uint64_t __tcp_errors = 0; // Deklariere den BME280 Kontext als externe globale Variable. // Dieser wird in main.cpp initialisiert und hier verwendet. extern bme280_ctx *ctx; // WICHTIG: Nutzt jetzt denselben Namen wie in main.cpp struct data { float t; float h; }; extern struct data _list[1000]; extern int list_index; extern int list_count; const char *html_page = R"rawliteral( Dashboard oder so

Dashboard oder so

🌡 Temp: -- °C
💧 Humidity: -- %

Temperature History

Humidity History

)rawliteral"; typedef struct HTTP_SERVER_T_ { struct tcp_pcb *server_pcb; struct tcp_pcb *client_pcb; } HTTP_SERVER_T; static HTTP_SERVER_T *http_server_init(void) { HTTP_SERVER_T *state = (HTTP_SERVER_T *)calloc(1, sizeof(HTTP_SERVER_T)); if (!state) { __tcp_errors++; DEBUG_printf("Failed to allocate HTTP server state\n"); return NULL; } return state; } static err_t http_server_close(void *arg) { HTTP_SERVER_T *state = (HTTP_SERVER_T *)arg; err_t err = ERR_OK; if (state->client_pcb != NULL) { tcp_arg(state->client_pcb, NULL); tcp_poll(state->client_pcb, NULL, 0); tcp_sent(state->client_pcb, NULL); tcp_recv(state->client_pcb, NULL); tcp_err(state->client_pcb, NULL); err = tcp_close(state->client_pcb); if (err != ERR_OK) { __tcp_errors++; DEBUG_printf("Close failed %d, calling abort\n", err); tcp_abort(state->client_pcb); err = ERR_ABRT; } state->client_pcb = NULL; } // Keep this off to keep the server alive // if (state->server_pcb) { // tcp_arg(state->server_pcb, NULL); // tcp_close(state->server_pcb); // state->server_pcb = NULL; //} return err; } static err_t http_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) { DEBUG_printf("HTTP data sent, length: %u\n", len); return http_server_close(arg); // Verbindung nach dem Senden schließen } static err_t http_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { HTTP_SERVER_T *state = (HTTP_SERVER_T *)arg; if (!p) { // Client hat Verbindung geschlossen return http_server_close(arg); } if (err != ERR_OK) { __tcp_errors++; DEBUG_printf("Error in TCP receive: %d\n", err); pbuf_free(p); return http_server_close(arg); } cyw43_arch_lwip_check(); // Eingehende Anfrage verarbeiten if (p->tot_len > 0) { char *req = (char *)malloc(p->tot_len + 1); if (req == NULL) { __tcp_errors++; DEBUG_printf("Failed to allocate memory for request\n"); pbuf_free(p); return http_server_close(arg); } pbuf_copy_partial(p, req, p->tot_len, 0); req[p->tot_len] = '\0'; // Request-String nullterminieren // DEBUG_printf("Received HTTP request:\n%s\n", req); // Einfaches Routing basierend auf der URL const char *http_header_ok_html = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: " "%d\r\nConnection: close\r\n\r\n"; const char *http_header_ok_json = "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: " "%d\r\nConnection: close\r\n\r\n"; const char *http_header_not_found = "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: " "13\r\nConnection: close\r\n\r\n"; const char *not_found_body = "404 Not Found"; char response_header[256]; const char *response_body; size_t response_body_len; char dynamic_json_body[256]; // Puffer für dynamische JSON-Daten char *history_body = 0; if (strstr(req, "GET / HTTP/1.1") || strstr(req, "GET /index.html HTTP/1.1")) { response_body = html_page; response_body_len = strlen(html_page); sprintf(response_header, http_header_ok_html, response_body_len); } else if (strstr(req, "GET /data HTTP/1.1")) { // Sensordaten auslesen float temp = 0.0; float humidity = 0.0; if (ctx != NULL) { // Zugriff auf die globale ctx Variable ctx->update(ctx); // Sensorwerte aktualisieren temp = ctx->read_temp(ctx); humidity = ctx->read_humidity(ctx); } else { DEBUG_printf("BME280 Kontext ist NULL, sende Standarddaten.\n"); } sprintf(dynamic_json_body, "{\"temp\": %.2f, \"humidity\": %.2f}", temp, humidity); response_body = dynamic_json_body; response_body_len = strlen(dynamic_json_body); sprintf(response_header, http_header_ok_json, response_body_len); } else if (strstr(req, "GET /history HTTP/1.1")) { history_body = (char *)malloc(4096); // or larger, depending on expected size if (!history_body) { __tcp_errors++; DEBUG_printf("Memory alloc failed for history\n"); free(req); pbuf_free(p); return http_server_close(arg); } char *ptr = history_body; ptr += sprintf(ptr, "["); for (int i = 0; i < list_count; i++) { int index = (list_index + i) % list_count; ptr += sprintf(ptr, "{\"t\":%.2f,\"h\":%.2f}%s", _list[index].t, _list[index].h, (i < list_count - 1) ? "," : ""); } ptr += sprintf(ptr, "]"); response_body = history_body; response_body_len = ptr - history_body; sprintf(response_header, http_header_ok_json, response_body_len); } else { response_body = not_found_body; response_body_len = strlen(not_found_body); sprintf(response_header, http_header_not_found, response_body_len); } // Header senden err_t wr_err = tcp_write(tpcb, response_header, strlen(response_header), TCP_WRITE_FLAG_MORE); if (wr_err != ERR_OK) { __tcp_errors++; DEBUG_printf("Failed to write header %d\n", wr_err); free(req); pbuf_free(p); return http_server_close(arg); } // Body senden wr_err = tcp_write(tpcb, response_body, response_body_len, TCP_WRITE_FLAG_COPY); if (wr_err != ERR_OK) { __tcp_errors++; DEBUG_printf("Failed to write body %d\n", wr_err); free(req); pbuf_free(p); return http_server_close(arg); } tcp_output(tpcb); // Sicherstellen, dass Daten gesendet werden if (history_body) { free(history_body); } free(req); } pbuf_free(p); tcp_recved(tpcb, p->tot_len); // Empfang der Daten bestätigen return ERR_OK; } static err_t http_server_poll(void *arg, struct tcp_pcb *tpcb) { // DEBUG_printf("HTTP server poll function called\n"); return ERR_OK; } static void http_server_err(void *arg, err_t err) { if (err != ERR_ABRT) { __tcp_errors++; DEBUG_printf("HTTP server error: %d\n", err); } } static err_t http_server_accept(void *arg, struct tcp_pcb *client_pcb, err_t err) { HTTP_SERVER_T *state = (HTTP_SERVER_T *)arg; if (err != ERR_OK || client_pcb == NULL) { __tcp_errors++; DEBUG_printf("Failure in accept: %d\n", err); return ERR_VAL; } DEBUG_printf("Client connected\n"); state->client_pcb = client_pcb; tcp_arg(client_pcb, state); tcp_sent(client_pcb, http_server_sent); tcp_recv(client_pcb, http_server_recv); tcp_poll(client_pcb, http_server_poll, POLL_TIME_S * 2); tcp_err(client_pcb, http_server_err); return ERR_OK; } bool http_server_open(void *arg) { HTTP_SERVER_T *state = (HTTP_SERVER_T *)arg; DEBUG_printf("Starting HTTP server at %s on port %u\n", ip4addr_ntoa(netif_ip4_addr(netif_list)), TCP_PORT); struct tcp_pcb *pcb = tcp_new_ip_type(IPADDR_TYPE_ANY); if (!pcb) { __tcp_errors++; DEBUG_printf("Failed to create pcb\n"); return false; } err_t err = tcp_bind(pcb, NULL, TCP_PORT); if (err) { __tcp_errors++; DEBUG_printf("Failed to bind to port %u\n", TCP_PORT); return false; } state->server_pcb = tcp_listen_with_backlog(pcb, 1); if (!state->server_pcb) { __tcp_errors++; DEBUG_printf("Failed to listen\n"); if (pcb) { tcp_close(pcb); } return false; } tcp_arg(state->server_pcb, state); tcp_accept(state->server_pcb, http_server_accept); return true; } // Funktion zum Initialisieren und Ausführen des HTTP-Servers in der // Hauptschleife void run_http_server(void) { static HTTP_SERVER_T *state = NULL; if (!state) { state = http_server_init(); if (!state) { return; } if (!http_server_open(state)) { http_server_close(state); free(state); state = NULL; return; } } #if PICO_CYW43_ARCH_POLL cyw43_arch_poll(); cyw43_arch_wait_for_work_until(make_timeout_time_ms(1)); #else sleep_ms(1); #endif }