#include "bme280.h" #include "pico/cyw43_arch.h" #include "pico/stdlib.h" #include "pms5003.h" #include "tcp_client.h" #include #include #include #include #include #include #include #include #include #include // 5 sec loop is for testing // #define LOOP_INTERVAL_MS 5000 #define LOOP_INTERVAL_MS 20000 // #define LOOP_INTERVAL_MS 30000 /** * Balcony Weather Station Node 1 * record sensor data and send it to home assistant every 5 minutes * Sensors: BME280, PMS5003 */ // COMMS LED absolute_time_t comms_led_off_time; int16_t comms_led_blink_count = 0; bool comms_led_state = false; void comms_led_init() { gpio_init(16); gpio_set_dir(16, GPIO_OUT); } void comms_led_blink() { printf("COMMS LED BLINK COUNT: %d\n", comms_led_blink_count); comms_led_blink_count++; comms_led_state = true; comms_led_off_time = make_timeout_time_ms(1000); gpio_put(16, comms_led_state); } void comms_led_update() { if (time_reached(comms_led_off_time)) { comms_led_state = false; gpio_put(16, comms_led_state); } } // Callback to reset the Pico after 24 hours static bool cb_24h(__unused struct repeating_timer *t) { printf("Restarting Pico after 24 hours...\n"); watchdog_enable(1, 1); // 1 ms timeout, reset on next loop while (1) { tight_loop_contents(); } // Wait for reset return false; // Not reached } static tcp_client_config tcp_config; static pms5003_config pms_config; static pms5003_reading current_pms5003_reading; static int8_t readings_index = 0; static bme280_config bem_config; static bme280_reading current_bem280_reading; // Initialize WiFi connection bool wifi_init(void) { printf("Initializing WiFi...\n"); if (cyw43_arch_init()) { printf("Failed to initialize CYW43\n"); return false; } cyw43_arch_enable_sta_mode(); printf("Connecting to WiFi '%s'...\n", WIFI_SSID); if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 60000)) { printf("Failed to connect to WiFi\n"); return false; } printf("WiFi connected successfully\n"); return true; } // Send a message over TCP to homeassistant event proxy static void send_msg(char *msg) { bool success = tcp_client_send_message(&tcp_config, msg); if (success) { printf("✓ Data sent successfully\n"); comms_led_blink(); } else { printf("✗ Failed to send data\n"); } } /** * Callback function called every 30 seconds */ char msg_to_send[256]; static bool do_work(void) { printf("cb_30: %d\n", readings_index); // Read BME280 printf("Making BME280 Reading\n"); current_bem280_reading = bme280_read(&bem_config); if (readings_index == 2) { printf("Warming up PMSS5003\n"); pms5003_warmup(&pms_config); } if (readings_index == 4) { printf("Starting reads on PMSS5003\n"); pms5003_start_reading(&pms_config); } if (readings_index == 6) { printf("Finished reading PMSS5003\n"); current_pms5003_reading = pms5003_finish_reading(&pms_config); } readings_index++; if (readings_index >= 10) { readings_index = 0; } snprintf(msg_to_send, sizeof(msg_to_send), "M001,%.2f,%.2f,%2f\n", current_bem280_reading.temperature, current_bem280_reading.pressure, current_bem280_reading.humidity); printf("Sending temperature, pressure, and humidity to backend server...\n"); send_msg(msg_to_send); // send PM readings if (readings_index == 6) { snprintf(msg_to_send, sizeof(msg_to_send), "M02,%.2f,%.2f,%2f\n", current_pms5003_reading.pm1, current_pms5003_reading.pm2_5, current_pms5003_reading.pm10); printf("Sending particulate matter readings to backend server...\n"); send_msg(msg_to_send); } return true; }; bool cb_30_trigger = true; static bool cb_30(__unused struct repeating_timer *t) { cb_30_trigger = true; } int main() { stdio_init_all(); watchdog_enable(60000, 1); sleep_ms(2000); // Give time for USB serial // Initialize communication LED comms_led_init(); // Initialize WiFi if (!wifi_init()) { panic("WiFi initialization failed!"); } if (!tcp_client_init(&tcp_config, BACKEND_SERVER_IP, BACKEND_SERVER_PORT, 20000)) { panic("TCP client initialization failed!"); } // Setup BME280 bme280_init(&bem_config, i2c1, 14, 15); // Setup PMS5003 pms5003_init(&pms_config, uart1, 20, 21, 18, 19); struct repeating_timer timer_30; add_repeating_timer_ms(LOOP_INTERVAL_MS, cb_30, NULL, &timer_30); struct repeating_timer timer_24h; add_repeating_timer_ms(86400000, cb_24h, NULL, &timer_24h); while (true) { cyw43_arch_poll(); cyw43_arch_wait_for_work_until(make_timeout_time_ms(1000)); comms_led_update(); watchdog_update(); tight_loop_contents(); // Iterate over msgs_to_send and send them if not empty if (cb_30_trigger) { do_work(); cb_30_trigger = false; } } } p