diff --git a/CMakeLists.txt b/CMakeLists.txt index d7952c8..e5964a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ add_custom_command( add_executable(sensor-pico src/main.cpp + src/time_sync.c src/webserver.c ) @@ -58,6 +59,7 @@ target_link_libraries(sensor-pico pico_lwip pico_lwip_http pico_lwip_mqtt + pico_lwip_sntp ) # Erzeugt .uf2 Datei zum Flashen diff --git a/lwipopts.h b/lwipopts.h index dfea587..c7734fb 100644 --- a/lwipopts.h +++ b/lwipopts.h @@ -1,6 +1,8 @@ #ifndef _LWIPOPTS_H #define _LWIPOPTS_H +#include + #define HTTPD_FSDATA_FILE "src/fsdata.c" #define NO_SYS 1 @@ -31,6 +33,20 @@ #define PBUF_POOL_SIZE 24 #define MEMP_NUM_SYS_TIMEOUT 20 +#define MQTT_OUTPUT_RINGBUF_SIZE 2048 + +#define SNTP_SERVER_DNS 1 +#define SNTP_SERVER_ADDRESS "de.pool.ntp.org" + +#ifdef __cplusplus +extern "C" { +#endif +void sntp_set_system_time_us(uint32_t sec, uint32_t us); +#ifdef __cplusplus +} +#endif +#define SNTP_SET_SYSTEM_TIME_US(sec, us) sntp_set_system_time_us((sec), (us)) + #define TCP_MSS 1460 #define TCP_WND (8 * TCP_MSS) #define TCP_SND_BUF (8 * TCP_MSS) diff --git a/src/main.cpp b/src/main.cpp index e02f6b4..8bd94e6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,12 +3,15 @@ #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 +#include static dhcp_server_t dhcp_server{}; @@ -61,14 +64,14 @@ void mqtt_cb(mqtt_client_t *client, void *arg, *mqtt_status = (status == MQTT_CONNECT_ACCEPTED) ? 0 : 1; } -int connect_to_mqtt() { +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 -1; + return nullptr; } if (!client) { client = mqtt_client_new(); @@ -84,11 +87,14 @@ int connect_to_mqtt() { cyw43_arch_poll(); sleep_ms(100); } - return mqtt_status; + if (mqtt_status == 0) { + return client; + } + return nullptr; } BME280_READING_INTERVALS_MS convert_Interval(int interval) { - if (interval < 1 && interval > 0) { + if (interval < 1) { return INTERVAL_0_5MS; } else if (interval < 20 && interval > 1) { return INTERVAL_10MS; @@ -109,12 +115,100 @@ BME280_READING_INTERVALS_MS convert_Interval(int interval) { } } +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(); @@ -125,30 +219,49 @@ int main() { } 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); } - mqtt_ret = connect_to_mqtt(); - if (!mqtt_ret) { - printf("Connected to mqtt!\n"); - break; - } else { + 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) { - bme280_read_data(handle); - printf("Messwerte: %s\n", bme280_get_json(handle)); - // publish_mqtt(); + 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(500); + sleep_ms(100); } } } diff --git a/src/time_sync.c b/src/time_sync.c new file mode 100644 index 0000000..4f655b4 --- /dev/null +++ b/src/time_sync.c @@ -0,0 +1,10 @@ +#include +#include +#include + +void sntp_set_system_time_us(uint32_t sec, uint32_t us) { + struct timeval tv; + tv.tv_sec = (time_t)sec; + tv.tv_usec = (suseconds_t)us; + settimeofday(&tv, NULL); +}