#include "bme280.h" #include "dhcp_server.h" #include "hardware/i2c.h" #include "lwip/apps/httpd.h" #include "lwip/apps/mqtt.h" #include "lwip/apps/sntp.h" #include "pico/cyw43_arch.h" #include "pico/stdlib.h" #include "webserver.h" #include #include #include #include #include static dhcp_server_t dhcp_server{}; void ap_init() { cyw43_arch_enable_ap_mode("SensorAP", "passwort123", CYW43_AUTH_WPA2_AES_PSK); ip_addr_t gw{}; ip_addr_t 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{}; memset(saved_ssid, 0, sizeof(saved_ssid)); memset(saved_password, 0, sizeof(saved_password)); ap_init(); while (saved_ssid[0] == '\0') { cyw43_arch_poll(); sleep_ms(100); } dhcp_server_deinit(&dhcp_server); cyw43_arch_disable_ap_mode(); 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; } void mqtt_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status) { int *mqtt_status{static_cast(arg)}; *mqtt_status = (status == MQTT_CONNECT_ACCEPTED) ? 0 : 1; } 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{}; if (!ipaddr_aton(saved_mqtt_address, &broker_ip)) { return nullptr; } if (!client) { client = mqtt_client_new(); } info.client_id = "sensor-pico"; info.client_user = saved_mqtt_user; info.client_pass = saved_mqtt_password; mqtt_status = -1; mqtt_client_connect(client, &broker_ip, saved_mqtt_port, mqtt_cb, &mqtt_status, &info); while (mqtt_status == -1) { cyw43_arch_poll(); sleep_ms(100); } if (mqtt_status == 0) { return client; } return 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; } } void publish_cb(void *arg, err_t err) { printf("Publish succesfull!\n"); } 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) { 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; return true; } 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; } float temperature, humidity, pressure; parse_json(raw, 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); snprintf(buffer, size, "{" "\"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; } void start_sntp() { cyw43_arch_lwip_begin(); if (sntp_enabled()) { sntp_stop(); } sntp_setoperatingmode(SNTP_OPMODE_POLL); #if SNTP_SERVER_DNS sntp_setservername(0, "de.pool.ntp.org"); #endif sntp_init(); cyw43_arch_lwip_end(); } 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(); sleep_ms(3000); 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()); while (true) { 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; } } cyw43_arch_poll(); sleep_ms(100); } } }