diff --git a/CMakeLists.txt b/CMakeLists.txt
index e5964a5..f95d1d1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -27,6 +27,7 @@ add_custom_command(
DEPENDS ${CMAKE_SOURCE_DIR}/fs/index.html
DEPENDS ${CMAKE_SOURCE_DIR}/fs/mqtt_config.html
DEPENDS ${CMAKE_SOURCE_DIR}/fs/wlan_config.html
+ DEPENDS ${CMAKE_SOURCE_DIR}/fs/live_stats.html
)
@@ -60,6 +61,8 @@ target_link_libraries(sensor-pico
pico_lwip_http
pico_lwip_mqtt
pico_lwip_sntp
+ hardware_flash
+ hardware_sync
)
# Erzeugt .uf2 Datei zum Flashen
diff --git a/fs/index.html b/fs/index.html
index 8a85291..5b6e590 100644
--- a/fs/index.html
+++ b/fs/index.html
@@ -1,16 +1,290 @@
-
+
- Config
+
+ Sensor Pico
+
- Sensor Pico
-
- Live Daten
-
- WLAN Config
-
- MQTT und Messungs Config
+
+
+
+
+
+
+
Temperatur
+
+ --
+ °C
+
+
+
🌡
+
+
+
+
Luftfeuchtigkeit
+
+ --
+ %
+
+
+
💧
+
+
+
+
Luftdruck
+
+ --
+ hPa
+
+
+
🔆
+
+
+
+
+
+
+
+
+
+
diff --git a/fs/live_stats.html b/fs/live_stats.html
index e69de29..bd13a4f 100644
--- a/fs/live_stats.html
+++ b/fs/live_stats.html
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/fs/mqtt_config.html b/fs/mqtt_config.html
index 0a80464..e6a3c7b 100644
--- a/fs/mqtt_config.html
+++ b/fs/mqtt_config.html
@@ -1,32 +1,189 @@
-
-
-
-
- Konfiguration
-
-
- MQTT Konfiguration
-
-
+
+
+
+
+ MQTT Konfiguration
+
+
+
+
+
diff --git a/fs/wlan_config.html b/fs/wlan_config.html
index e310c89..69eef78 100644
--- a/fs/wlan_config.html
+++ b/fs/wlan_config.html
@@ -1,20 +1,141 @@
-
-
-
-
- Konfiguration
-
-
- WLAN Einstellungen
-
-
+
+
+
+
+ WLAN Konfiguration
+
+
+
+
+
diff --git a/lwipopts.h b/lwipopts.h
index c7734fb..22a84b9 100644
--- a/lwipopts.h
+++ b/lwipopts.h
@@ -23,6 +23,7 @@
#define LWIP_HTTPD_CGI 1
#define LWIP_HTTPD_SSI 1
#define LWIP_HTTPD_SUPPORT_POST 1
+#define LWIP_HTTPD_CUSTOM_FILES 1
#define LWIP_NETIF_HOSTNAME 1
#define LWIP_NETIF_STATUS_CALLBACK 1
diff --git a/src/main.cpp b/src/main.cpp
index 8bd94e6..6f7a077 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -15,28 +15,21 @@
static dhcp_server_t dhcp_server{};
-void ap_init() {
- cyw43_arch_enable_ap_mode("SensorAP", "passwort123", CYW43_AUTH_WPA2_AES_PSK);
+/* ── WiFi ───────────────────────────────────────────────────────────────────
+ */
- ip_addr_t gw{};
- ip_addr_t mask{};
+static void ap_init() {
+ cyw43_arch_enable_ap_mode("SensorAP", "passwort123", CYW43_AUTH_WPA2_AES_PSK);
+ ip_addr_t gw{}, mask{};
IP4_ADDR(&gw, 192, 168, 4, 1);
IP4_ADDR(&mask, 255, 255, 255, 0);
-
dhcp_server_deinit(&dhcp_server);
dhcp_server_init(&dhcp_server, &gw, &mask);
}
-void reset_mqtt_config() {
- memset(saved_mqtt_address, 0, sizeof(saved_mqtt_address));
- memset(saved_mqtt_user, 0, sizeof(saved_mqtt_user));
- memset(saved_mqtt_password, 0, sizeof(saved_mqtt_password));
- saved_measure_frequency = 0;
- saved_post_frequency = 0;
-}
-
-int connect_to_wifi() {
- int ret{};
+/* Open AP, wait for user to POST credentials, then connect STA.
+ Returns 0 on success. */
+static int connect_via_ap() {
memset(saved_ssid, 0, sizeof(saved_ssid));
memset(saved_password, 0, sizeof(saved_password));
ap_init();
@@ -49,33 +42,41 @@ int connect_to_wifi() {
cyw43_arch_disable_sta_mode();
sleep_ms(500);
cyw43_arch_enable_sta_mode();
-
- ret = cyw43_arch_wifi_connect_timeout_ms(saved_ssid, saved_password,
- CYW43_AUTH_WPA2_MIXED_PSK, 30000);
- if (ret == 0) {
- return 0;
- }
- return -1;
+ return cyw43_arch_wifi_connect_timeout_ms(saved_ssid, saved_password,
+ CYW43_AUTH_WPA2_MIXED_PSK, 30000);
}
-void mqtt_cb(mqtt_client_t *client, void *arg,
- mqtt_connection_status_t status) {
+/* Connect STA with current saved credentials (no AP fallback). */
+static int connect_sta() {
+ cyw43_arch_disable_sta_mode();
+ sleep_ms(500);
+ cyw43_arch_enable_sta_mode();
+ return cyw43_arch_wifi_connect_timeout_ms(saved_ssid, saved_password,
+ CYW43_AUTH_WPA2_MIXED_PSK, 30000);
+}
+
+/* ── MQTT ───────────────────────────────────────────────────────────────────
+ */
+
+static void mqtt_cb(mqtt_client_t *client, void *arg,
+ mqtt_connection_status_t status) {
+ (void)client;
int *mqtt_status{static_cast(arg)};
*mqtt_status = (status == MQTT_CONNECT_ACCEPTED) ? 0 : 1;
}
-mqtt_client_t *connect_to_mqtt() {
+static mqtt_client_t *connect_to_mqtt() {
static int mqtt_status{-1};
- ip_addr_t broker_ip;
static mqtt_client_t *client{};
static mqtt_connect_client_info_t info{};
+ ip_addr_t broker_ip;
- if (!ipaddr_aton(saved_mqtt_address, &broker_ip)) {
+ if (!ipaddr_aton(saved_mqtt_address, &broker_ip))
return nullptr;
- }
- if (!client) {
+
+ if (!client)
client = mqtt_client_new();
- }
+
info.client_id = "sensor-pico";
info.client_user = saved_mqtt_user;
info.client_pass = saved_mqtt_password;
@@ -87,70 +88,62 @@ mqtt_client_t *connect_to_mqtt() {
cyw43_arch_poll();
sleep_ms(100);
}
- if (mqtt_status == 0) {
- return client;
- }
- return nullptr;
+ return (mqtt_status == 0) ? client : nullptr;
}
-BME280_READING_INTERVALS_MS convert_Interval(int interval) {
- if (interval < 1) {
- return INTERVAL_0_5MS;
- } else if (interval < 20 && interval > 1) {
- return INTERVAL_10MS;
- } else if (interval < 30 && interval > 10) {
- return INTERVAL_20MS;
- } else if (interval < 125 && interval > 20) {
- return INTERVAL_62_5MS;
- } else if (interval < 250 && interval > 62.5) {
- return INTERVAL_125MS;
- } else if (interval < 500 && interval > 125) {
- return INTERVAL_250MS;
- } else if (interval < 1000 && interval > 250) {
- return INTERVAL_500MS;
- } else if (interval > 1000) {
- return INTERVAL_1000MS;
- } else {
- return INTERVAL_500MS;
- }
+static void publish_cb(void *arg, err_t err) {
+ (void)arg;
+ (void)err;
+ printf("Publish successful!\n");
}
-void publish_cb(void *arg, err_t err) { printf("Publish succesfull!\n"); }
-
-void publish_mqtt(mqtt_client_t *client, const char *payload) {
+static void publish_mqtt(mqtt_client_t *client, const char *payload) {
uint payload_len{strlen(payload)};
mqtt_publish(client, "tele/sensor-pico/SENSOR", payload, payload_len, 1, 1,
publish_cb, nullptr);
}
-bool parse_json(const char *raw, float &temperature, float &humidity,
- float &pressure) {
+/* ── BME280 ─────────────────────────────────────────────────────────────────
+ */
+
+static BME280_READING_INTERVALS_MS convert_interval(int ms) {
+ if (ms < 1)
+ return INTERVAL_0_5MS;
+ if (ms < 20)
+ return INTERVAL_10MS;
+ if (ms < 30)
+ return INTERVAL_20MS;
+ if (ms < 125)
+ return INTERVAL_62_5MS;
+ if (ms < 250)
+ return INTERVAL_125MS;
+ if (ms < 500)
+ return INTERVAL_250MS;
+ if (ms < 1000)
+ return INTERVAL_500MS;
+ return INTERVAL_1000MS;
+}
+
+static bool parse_json(const char *raw, float &temperature, float &humidity,
+ float &pressure) {
if (!raw)
return false;
-
const char *t_ptr = std::strstr(raw, "\"temperature\":");
const char *h_ptr = std::strstr(raw, "\"humidity\":");
const char *p_ptr = std::strstr(raw, "\"pressure\":");
-
if (!t_ptr || !h_ptr || !p_ptr)
return false;
-
- long t_raw = std::strtol(t_ptr + 14, nullptr, 10);
- long h_raw = std::strtol(h_ptr + 11, nullptr, 10);
- long p_raw = std::strtol(p_ptr + 11, nullptr, 10);
-
- temperature = t_raw / 100.0f;
- humidity = h_raw / 1024.0f;
- pressure = p_raw / 25600.0f;
-
+ temperature = std::strtol(t_ptr + 14, nullptr, 10) / 100.0f;
+ humidity = std::strtol(h_ptr + 11, nullptr, 10) / 1024.0f;
+ pressure = std::strtol(p_ptr + 11, nullptr, 10) / 25600.0f;
return true;
}
-void build_sensor_payload(char *buffer, size_t size, bme280_handle_t handle,
- const char *sensor_name) {
+static void build_sensor_payload(char *buffer, size_t size,
+ bme280_handle_t handle,
+ const char *sensor_name) {
bme280_read_data(handle);
const char *raw = bme280_get_json(handle);
-
if (!raw) {
snprintf(buffer, size, "{\"error\":\"no data\"}");
return;
@@ -158,37 +151,32 @@ void build_sensor_payload(char *buffer, size_t size, bme280_handle_t handle,
float temperature, humidity, pressure;
parse_json(raw, temperature, humidity, pressure);
+ webserver_update_sensor(temperature, humidity, pressure);
time_t now;
time(&now);
- struct tm *timeinfo = localtime(&now);
-
char time_str[32];
- strftime(time_str, sizeof(time_str), "%Y-%m-%dT%H:%M:%S", timeinfo);
+ strftime(time_str, sizeof(time_str), "%Y-%m-%dT%H:%M:%S", localtime(&now));
snprintf(buffer, size,
- "{"
- "\"Time\":\"%s\","
- "\"%s\":{"
- "\"Temperature\":%.2f,"
- "\"Humidity\":%.2f,"
- "\"Pressure\":%.2f"
- "},"
- "\"TempUnit\":\"C\""
- "}",
+ "{\"Time\":\"%s\",\"%s\":{"
+ "\"Temperature\":%.2f,\"Humidity\":%.2f,\"Pressure\":%.2f"
+ "},\"TempUnit\":\"C\"}",
time_str, sensor_name, temperature, humidity, pressure);
}
-bool is_time_synced() {
- time_t now = time(NULL);
- struct tm *timeinfo = localtime(&now);
- return timeinfo->tm_year > 70;
+
+/* ── SNTP ───────────────────────────────────────────────────────────────────
+ */
+
+static bool is_time_synced() {
+ time_t now = time(nullptr);
+ return localtime(&now)->tm_year > 70;
}
-void start_sntp() {
+static void start_sntp() {
cyw43_arch_lwip_begin();
- if (sntp_enabled()) {
+ if (sntp_enabled())
sntp_stop();
- }
sntp_setoperatingmode(SNTP_OPMODE_POLL);
#if SNTP_SERVER_DNS
sntp_setservername(0, "de.pool.ntp.org");
@@ -197,15 +185,10 @@ void start_sntp() {
cyw43_arch_lwip_end();
}
+/* ── Main ───────────────────────────────────────────────────────────────────
+ */
+
int main() {
- uint32_t last_publish{};
- uint32_t last_sntp_retry_ms{};
- int mqtt_ret{-1};
- int wifi_status{1};
- int bme_status{-1};
- char payload[256];
- mqtt_client_t *client{};
- bme280_handle_t handle{};
stdio_init_all();
setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0", 1);
tzset();
@@ -213,55 +196,117 @@ int main() {
cyw43_arch_init();
httpd_init();
- while (wifi_status != 0) {
- wifi_status = (connect_to_wifi() == 0) ? 0 : 1;
- printf("Wifi status: %d\n", wifi_status);
- }
- printf("Connected to wifi!\n");
- printf("IP: %s\n", ip4addr_ntoa(netif_ip4_addr(netif_default)));
- start_sntp();
- last_sntp_retry_ms = to_ms_since_boot(get_absolute_time());
+ /* ── 1. Load config from flash ── */
+ bool has_saved_config = config_load();
+ /* ── 2. Connect to WiFi ── */
+ if (has_saved_config && saved_ssid[0] != '\0') {
+ printf("Trying saved WiFi: %s\n", saved_ssid);
+ if (connect_sta() != 0) {
+ printf("Saved WiFi failed, opening AP...\n");
+ while (connect_via_ap() != 0) {
+ printf("AP connect failed, retrying...\n");
+ }
+ }
+ } else {
+ while (connect_via_ap() != 0) {
+ printf("AP connect failed, retrying...\n");
+ }
+ }
+ printf("WiFi connected! IP: %s\n",
+ ip4addr_ntoa(netif_ip4_addr(netif_default)));
+
+ start_sntp();
+ uint32_t last_sntp_retry_ms = to_ms_since_boot(get_absolute_time());
+
+ /* ── 3. Wait for MQTT config if not saved ── */
+ while (saved_mqtt_address[0] == '\0') {
+ cyw43_arch_poll();
+ sleep_ms(200);
+ }
+
+ /* ── 4. Connect to MQTT ── */
+ mqtt_client_t *client{};
while (true) {
+ client = connect_to_mqtt();
+ if (client)
+ break;
+ printf("MQTT connect failed, waiting for new config...\n");
+ memset(saved_mqtt_address, 0, sizeof(saved_mqtt_address));
while (saved_mqtt_address[0] == '\0') {
cyw43_arch_poll();
sleep_ms(200);
}
- client = connect_to_mqtt();
- if (client == nullptr) {
- printf("Mqtt Status: %d\n", mqtt_ret);
- reset_mqtt_config();
- } else {
- printf("Connected to mqtt!\n");
- break;
- }
}
- bme_status =
- bme280_init(&handle, 0x76, convert_Interval(saved_measure_frequency));
- if (!bme_status) {
- last_publish = to_ms_since_boot(get_absolute_time());
- while (true) {
- if ((to_ms_since_boot(get_absolute_time()) - last_publish) >=
- saved_post_frequency * 1000) {
- if (is_time_synced()) {
- build_sensor_payload(payload, sizeof(payload), handle, "BME280");
- publish_mqtt(client, payload);
- printf("Payload: %s\n", payload);
- last_publish = to_ms_since_boot(get_absolute_time());
- } else {
- printf("Waiting for SNTP sync (Current year: 1970)...\n");
- uint32_t now_ms = to_ms_since_boot(get_absolute_time());
- if (now_ms - last_sntp_retry_ms > 30000) {
- printf("Retrying SNTP...\n");
- start_sntp();
- last_sntp_retry_ms = now_ms;
- }
- last_publish = to_ms_since_boot(get_absolute_time()) -
- (saved_post_frequency * 1000) + 5000;
- }
+ printf("MQTT connected!\n");
+
+ /* ── 5. Init BME280 ── */
+ bme280_handle_t handle{};
+ bool bme_ok = (bme280_init(&handle, 0x76,
+ convert_interval(saved_measure_frequency)) == 0);
+
+ char payload[256];
+ uint32_t last_publish = to_ms_since_boot(get_absolute_time());
+
+ /* ── 6. Main loop ── */
+ while (true) {
+
+ /* ── Handle WiFi config change ── */
+ if (wlan_config_updated) {
+ wlan_config_updated = false;
+ config_save();
+ printf("WiFi config updated, reconnecting...\n");
+ if (mqtt_client_is_connected(client))
+ mqtt_disconnect(client);
+ if (connect_sta() == 0) {
+ printf("WiFi reconnected!\n");
+ start_sntp();
+ last_sntp_retry_ms = to_ms_since_boot(get_absolute_time());
+ } else {
+ printf("WiFi reconnect failed!\n");
}
- cyw43_arch_poll();
- sleep_ms(100);
+ /* Force MQTT reconnect after WiFi change */
+ mqtt_config_updated = true;
}
+
+ /* ── Handle MQTT / interval config change ── */
+ if (mqtt_config_updated) {
+ mqtt_config_updated = false;
+ config_save();
+ printf("MQTT config updated, reconnecting...\n");
+ if (mqtt_client_is_connected(client))
+ mqtt_disconnect(client);
+ client = connect_to_mqtt();
+ if (client) {
+ printf("MQTT reconnected!\n");
+ bme_ok = (bme280_init(&handle, 0x76,
+ convert_interval(saved_measure_frequency)) == 0);
+ last_publish = to_ms_since_boot(get_absolute_time());
+ } else {
+ printf("MQTT reconnect failed!\n");
+ }
+ }
+
+ /* ── Periodic publish ── */
+ uint32_t now_ms = to_ms_since_boot(get_absolute_time());
+ if (client && bme_ok &&
+ (now_ms - last_publish) >= uint32_t(saved_post_frequency) * 1000) {
+ if (is_time_synced()) {
+ build_sensor_payload(payload, sizeof(payload), handle, "BME280");
+ publish_mqtt(client, payload);
+ printf("Payload: %s\n", payload);
+ last_publish = now_ms;
+ } else {
+ printf("Waiting for SNTP sync...\n");
+ if (now_ms - last_sntp_retry_ms > 30000) {
+ start_sntp();
+ last_sntp_retry_ms = now_ms;
+ }
+ last_publish = now_ms - uint32_t(saved_post_frequency) * 1000 + 5000;
+ }
+ }
+
+ cyw43_arch_poll();
+ sleep_ms(100);
}
}
diff --git a/src/webserver.c b/src/webserver.c
index a22664a..88c1f49 100644
--- a/src/webserver.c
+++ b/src/webserver.c
@@ -1,20 +1,141 @@
#include "lwip/apps/httpd.h"
+#include "lwip/apps/fs.h"
+#include "hardware/flash.h"
+#include "hardware/sync.h"
+#include "pico/platform.h"
#include "string.h"
+#include
#include
#include
+#include
+
+/* ── Sensor data endpoint ─────────────────────────────────────────────────── */
+
+static char sensor_response[256];
+static int sensor_response_len = 0;
+
+void webserver_update_sensor(float temperature, float humidity, float pressure) {
+ const char *hdr = "HTTP/1.0 200 OK\r\n"
+ "Content-Type: application/json\r\n"
+ "\r\n";
+ char body[96];
+ int blen = snprintf(body, sizeof(body),
+ "{\"temperature\":%.2f,\"humidity\":%.2f,\"pressure\":%.2f}",
+ temperature, humidity, pressure);
+ int hlen = strlen(hdr);
+ if (hlen + blen < (int)sizeof(sensor_response)) {
+ memcpy(sensor_response, hdr, hlen);
+ memcpy(sensor_response + hlen, body, blen);
+ sensor_response_len = hlen + blen;
+ }
+}
+
+int fs_open_custom(struct fs_file *file, const char *name) {
+ if (strcmp(name, "/sensor-data.json") == 0) {
+ memset(file, 0, sizeof(struct fs_file));
+ file->data = sensor_response;
+ file->len = sensor_response_len;
+ file->index = sensor_response_len;
+ file->flags = FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT;
+ return 1;
+ }
+ return 0;
+}
+
+void fs_close_custom(struct fs_file *file) {
+ (void)file;
+}
+
+/* ── Saved config variables ───────────────────────────────────────────────── */
char saved_ssid[33];
char saved_password[65];
char saved_mqtt_address[65];
char saved_mqtt_user[33];
char saved_mqtt_password[65];
-int saved_measure_frequency;
-int saved_post_frequency;
-int saved_mqtt_port;
+int saved_measure_frequency;
+int saved_post_frequency;
+int saved_mqtt_port;
-static int post_state;
+/* ── Config update flags (set by POST handlers, read in main loop) ────────── */
-static char post_buffer[400];
+volatile bool wlan_config_updated = false;
+volatile bool mqtt_config_updated = false;
+
+/* ── Flash persistence ────────────────────────────────────────────────────── */
+
+#define FLASH_CONFIG_MAGIC 0xC0DECAFEu
+#define FLASH_CONFIG_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE)
+
+typedef struct {
+ uint32_t magic;
+ char ssid[33];
+ char password[65];
+ char mqtt_address[65];
+ char mqtt_user[33];
+ char mqtt_password[65];
+ int32_t mqtt_port;
+ int32_t measure_frequency;
+ int32_t post_frequency;
+} config_t;
+
+_Static_assert(sizeof(config_t) <= FLASH_PAGE_SIZE * 2,
+ "config_t does not fit in 2 flash pages");
+
+void config_save(void) {
+ static uint8_t buf[FLASH_PAGE_SIZE * 2];
+ memset(buf, 0xff, sizeof(buf));
+
+ config_t *cfg = (config_t *)buf;
+ cfg->magic = FLASH_CONFIG_MAGIC;
+ strncpy(cfg->ssid, saved_ssid, sizeof(cfg->ssid) - 1);
+ strncpy(cfg->password, saved_password, sizeof(cfg->password) - 1);
+ strncpy(cfg->mqtt_address, saved_mqtt_address, sizeof(cfg->mqtt_address) - 1);
+ strncpy(cfg->mqtt_user, saved_mqtt_user, sizeof(cfg->mqtt_user) - 1);
+ strncpy(cfg->mqtt_password, saved_mqtt_password, sizeof(cfg->mqtt_password) - 1);
+ cfg->mqtt_port = (int32_t)saved_mqtt_port;
+ cfg->measure_frequency = (int32_t)saved_measure_frequency;
+ cfg->post_frequency = (int32_t)saved_post_frequency;
+
+ uint32_t ints = save_and_disable_interrupts();
+ flash_range_erase(FLASH_CONFIG_OFFSET, FLASH_SECTOR_SIZE);
+ flash_range_program(FLASH_CONFIG_OFFSET, buf, sizeof(buf));
+ restore_interrupts(ints);
+
+ printf("Config saved to flash\n");
+}
+
+bool config_load(void) {
+ const config_t *cfg =
+ (const config_t *)(uintptr_t)(XIP_BASE + FLASH_CONFIG_OFFSET);
+
+ if (cfg->magic != FLASH_CONFIG_MAGIC) {
+ printf("No valid config in flash\n");
+ return false;
+ }
+
+ strncpy(saved_ssid, cfg->ssid, sizeof(saved_ssid) - 1);
+ strncpy(saved_password, cfg->password, sizeof(saved_password) - 1);
+ strncpy(saved_mqtt_address, cfg->mqtt_address, sizeof(saved_mqtt_address) - 1);
+ strncpy(saved_mqtt_user, cfg->mqtt_user, sizeof(saved_mqtt_user) - 1);
+ strncpy(saved_mqtt_password, cfg->mqtt_password, sizeof(saved_mqtt_password) - 1);
+ saved_ssid[sizeof(saved_ssid) - 1] = '\0';
+ saved_password[sizeof(saved_password) - 1] = '\0';
+ saved_mqtt_address[sizeof(saved_mqtt_address) - 1] = '\0';
+ saved_mqtt_user[sizeof(saved_mqtt_user) - 1] = '\0';
+ saved_mqtt_password[sizeof(saved_mqtt_password) - 1] = '\0';
+ saved_mqtt_port = (int)cfg->mqtt_port;
+ saved_measure_frequency = (int)cfg->measure_frequency;
+ saved_post_frequency = (int)cfg->post_frequency;
+
+ printf("Config loaded from flash\n");
+ return true;
+}
+
+/* ── POST parsing helper ──────────────────────────────────────────────────── */
+
+static int post_state;
+static char post_buffer[400];
static uint16_t post_buffer_len = 0;
void parse_post(const char *key, char delimiter, char *dest, int max_len) {
@@ -27,24 +148,24 @@ void parse_post(const char *key, char delimiter, char *dest, int max_len) {
char *pos = start + strlen(key);
char *end = (delimiter == '\0') ? (post_buffer + strlen(post_buffer))
: strchr(pos, delimiter);
-
- if (!end) {
+ if (!end)
end = post_buffer + strlen(post_buffer);
- }
int len = end - pos;
- if (len > max_len) {
+ if (len > max_len)
len = max_len;
- }
strncpy(dest, pos, len);
dest[len] = '\0';
}
+/* ── lwip httpd POST callbacks ────────────────────────────────────────────── */
+
err_t httpd_post_begin(void *connection, const char *uri,
const char *http_request, u16_t http_request_len,
int content_len, char *response_uri,
u16_t response_uri_len, u8_t *post_auto_wnd) {
+ (void)connection; (void)http_request; (void)http_request_len; (void)content_len;
if (strcmp(uri, "/wlan-config") == 0) {
strncpy(response_uri, "/wlan_config.html", response_uri_len);
*post_auto_wnd = 1;
@@ -52,15 +173,16 @@ err_t httpd_post_begin(void *connection, const char *uri,
return ERR_OK;
}
if (strcmp(uri, "/mqtt-config") == 0) {
- post_state = 1;
strncpy(response_uri, "/mqtt_config.html", response_uri_len);
*post_auto_wnd = 1;
+ post_state = 1;
return ERR_OK;
}
return ERR_VAL;
}
err_t httpd_post_receive_data(void *connection, struct pbuf *p) {
+ (void)connection;
post_buffer_len =
pbuf_copy_partial(p, post_buffer, sizeof(post_buffer) - 1, 0);
post_buffer[post_buffer_len] = '\0';
@@ -70,27 +192,25 @@ err_t httpd_post_receive_data(void *connection, struct pbuf *p) {
void httpd_post_finished(void *connection, char *response_uri,
u16_t response_uri_len) {
+ (void)connection;
if (post_state == 0) {
strncpy(response_uri, "/wlan_config.html", response_uri_len);
-
- parse_post("ssid=", '&', saved_ssid, 32);
- parse_post("password=", '\0', saved_password, 64);
+ parse_post("ssid=", '&', saved_ssid, 32);
+ parse_post("password=", '\0', saved_password, 64);
+ wlan_config_updated = true;
} else if (post_state == 1) {
char temp[16];
strncpy(response_uri, "/mqtt_config.html", response_uri_len);
-
- parse_post("mqtt-address=", '&', saved_mqtt_address, 64);
- parse_post("mqtt-user=", '&', saved_mqtt_user, 32);
- parse_post("mqtt-password=", '&', saved_mqtt_password, 64);
-
- parse_post("mqtt-port=", '&', temp, 15);
+ parse_post("mqtt-address=", '&', saved_mqtt_address, 64);
+ parse_post("mqtt-user=", '&', saved_mqtt_user, 32);
+ parse_post("mqtt-password=", '&', saved_mqtt_password, 64);
+ parse_post("mqtt-port=", '&', temp, 15);
saved_mqtt_port = atoi(temp);
-
parse_post("measure-frequency=", '&', temp, 15);
saved_measure_frequency = atoi(temp);
-
- parse_post("push-frequency=", '\0', temp, 15);
+ parse_post("push-frequency=", '\0', temp, 15);
saved_post_frequency = atoi(temp);
+ mqtt_config_updated = true;
}
}
diff --git a/src/webserver.h b/src/webserver.h
index cd09fde..cc35156 100644
--- a/src/webserver.h
+++ b/src/webserver.h
@@ -1,18 +1,32 @@
#ifndef WEBSERVER_H
#define WEBSERVER_H
+#include
+
#ifdef __cplusplus
extern "C" {
#endif
+/* Saved configuration (written by POST handlers, read by main) */
extern char saved_ssid[33];
extern char saved_password[65];
extern char saved_mqtt_address[65];
extern char saved_mqtt_user[33];
extern char saved_mqtt_password[65];
-extern int saved_measure_frequency;
-extern int saved_post_frequency;
-extern int saved_mqtt_port;
+extern int saved_measure_frequency;
+extern int saved_post_frequency;
+extern int saved_mqtt_port;
+
+/* Set by POST handlers when new config arrives; cleared by main after handling */
+extern volatile bool wlan_config_updated;
+extern volatile bool mqtt_config_updated;
+
+/* Flash persistence */
+void config_save(void);
+bool config_load(void);
+
+/* Sensor data for live dashboard */
+void webserver_update_sensor(float temperature, float humidity, float pressure);
#ifdef __cplusplus
}