/* _ _ _____ _______ _____ ____ _ __ | \ | | ____|_ _\ \ / / _ \| _ \| |/ / | \| | _| | | \ \ /\ / / | | | |_) | ' / | |\ | |___ | | \ V V /| |_| | _ <| . \ |_| \_|_____| |_| \_/\_/ \___/|_| \_\_|\_\ Modern Network Status Display (4G + WiFi) Get 4G status, signal quality, and WiFi status from SQLite database config_table Pour compiler: g++ -I/var/www/moduleair_pro_4g/matrix/include -L/var/www/moduleair_pro_4g/matrix/lib /var/www/moduleair_pro_4g/matrix/screenNetwork/network_status.cc -o /var/www/moduleair_pro_4g/matrix/screenNetwork/network_status -lrgbmatrix -lsqlite3 Pour lancer: sudo /var/www/moduleair_pro_4g/matrix/screenNetwork/network_status */ #include "led-matrix.h" #include "graphics.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using rgb_matrix::RGBMatrix; using rgb_matrix::Canvas; std::atomic running(true); // Define color codes for console output #define RESET "\033[0m" #define RED "\033[31m" #define GREEN "\033[32m" #define YELLOW "\033[33m" #define BLUE "\033[34m" #define MAGENTA "\033[35m" #define CYAN "\033[36m" #define WHITE "\033[37m" // Path to the SQLite database const std::string DB_PATH = "/var/www/moduleair_pro_4g/sqlite/sensors.db"; // Animation counter for connection indicators int animation_frame = 0; void signal_handler(int signum) { running = false; } void log(const std::string& type, const std::string& message) { std::string color; if (type == "BLUE") color = BLUE; else if (type == "GREEN") color = GREEN; else if (type == "YELLOW") color = YELLOW; else if (type == "RED") color = RED; else color = WHITE; std::cout << color << message << RESET << std::endl; } // Function to get WiFi status from database bool get_wifi_status(sqlite3* db, std::string& wifi_status) { sqlite3_stmt* stmt; bool status_found = false; log("BLUE", "Querying WiFi status from database..."); const char* query = "SELECT value FROM config_table WHERE key='WIFI_status'"; if (sqlite3_prepare_v2(db, query, -1, &stmt, NULL) == SQLITE_OK) { if (sqlite3_step(stmt) == SQLITE_ROW) { wifi_status = (char*)sqlite3_column_text(stmt, 0); status_found = true; std::cout << " WiFi Status: " << wifi_status << std::endl; } else { std::cout << " No WiFi status found in config_table" << std::endl; wifi_status = "unknown"; } sqlite3_finalize(stmt); } return status_found; } // Function to get 4G status from database bool get_4g_status(sqlite3* db, std::string& network_status, int& signal_quality) { sqlite3_stmt* stmt; bool status_found = false; bool signal_found = false; log("BLUE", "Querying 4G status from database..."); // Get network status const char* status_query = "SELECT value FROM config_table WHERE key='SARA_network_status'"; if (sqlite3_prepare_v2(db, status_query, -1, &stmt, NULL) == SQLITE_OK) { if (sqlite3_step(stmt) == SQLITE_ROW) { network_status = (char*)sqlite3_column_text(stmt, 0); status_found = true; std::cout << " Network Status: " << network_status << std::endl; } else { std::cout << " No network status found in config_table" << std::endl; network_status = "unknown"; } sqlite3_finalize(stmt); } // Get signal quality const char* signal_query = "SELECT value FROM config_table WHERE key='SARA_signal_quality'"; if (sqlite3_prepare_v2(db, signal_query, -1, &stmt, NULL) == SQLITE_OK) { if (sqlite3_step(stmt) == SQLITE_ROW) { signal_quality = sqlite3_column_int(stmt, 0); signal_found = true; std::cout << " Signal Quality: " << signal_quality << " dBm" << std::endl; } else { std::cout << " No signal quality found in config_table" << std::endl; signal_quality = -999; } sqlite3_finalize(stmt); } return status_found || signal_found; } // Function to draw signal strength bars void draw_signal_bars(Canvas* canvas, int x, int y, int signal_rssi) { rgb_matrix::Color bar_color; rgb_matrix::Color bg_color(0, 0, 0); // Convert RSSI to signal strength (0-5 bars) // RSSI scale: 0-31 (where 31 is strongest) int bars = 0; if (signal_rssi >= 20) bars = 5; // Excellent (20-31) else if (signal_rssi >= 15) bars = 4; // Good (15-19) else if (signal_rssi >= 10) bars = 3; // Fair (10-14) else if (signal_rssi >= 5) bars = 2; // Poor (5-9) else if (signal_rssi >= 1) bars = 1; // Very Poor (1-4) else bars = 0; // No signal (0) // Choose color based on signal strength if (bars >= 4) bar_color = rgb_matrix::Color(0, 255, 0); // Green - Excellent/Good else if (bars >= 2) bar_color = rgb_matrix::Color(255, 255, 0); // Yellow - Fair/Poor else if (bars >= 1) bar_color = rgb_matrix::Color(255, 165, 0); // Orange - Very Poor else bar_color = rgb_matrix::Color(255, 0, 0); // Red - No signal // Draw 5 signal bars of increasing height for (int i = 0; i < 5; i++) { int bar_height = (i + 1) * 2; // Heights: 2, 4, 6, 8, 10 int bar_x = x + i * 3; // Clear the bar area first for (int bx = 0; bx < 2; bx++) { for (int by = 0; by < 10; by++) { canvas->SetPixel(bar_x + bx, y - by, 0, 0, 0); } } // Draw the bar if it should be active if (i < bars) { for (int bx = 0; bx < 2; bx++) { for (int by = 0; by < bar_height; by++) { canvas->SetPixel(bar_x + bx, y - by, bar_color.r, bar_color.g, bar_color.b); } } } } } // Function to draw connection status icon void draw_connection_icon(Canvas* canvas, int x, int y, const std::string& status) { rgb_matrix::Color icon_color; // Clear the icon area (20x20 pixels) for (int ix = 0; ix < 20; ix++) { for (int iy = 0; iy < 20; iy++) { canvas->SetPixel(x + ix, y + iy, 0, 0, 0); } } if (status == "connected") { icon_color = rgb_matrix::Color(0, 255, 0); // Green // Draw a checkmark // Simplified checkmark pattern for (int i = 0; i < 6; i++) { canvas->SetPixel(x + 5 + i, y + 10 + i/2, icon_color.r, icon_color.g, icon_color.b); canvas->SetPixel(x + 11 + i, y + 13 - i, icon_color.r, icon_color.g, icon_color.b); } } else if (status == "connecting") { // Animated connecting indicator icon_color = rgb_matrix::Color(255, 255, 0); // Yellow int frame = animation_frame % 8; // Draw rotating dots for (int i = 0; i < 8; i++) { if (i <= frame) { int dot_x = x + 10 + (int)(8 * cos(i * M_PI / 4)); int dot_y = y + 10 + (int)(8 * sin(i * M_PI / 4)); canvas->SetPixel(dot_x, dot_y, icon_color.r, icon_color.g, icon_color.b); canvas->SetPixel(dot_x+1, dot_y, icon_color.r, icon_color.g, icon_color.b); } } } else if (status == "booting") { icon_color = rgb_matrix::Color(255, 255, 0); // Changed from orange to yellow // Draw a simple but visible rotating indicator for booting - EVEN FASTER rotation int frame = (animation_frame / 2) % 2; // Much faster rotation - update every 2 frames // Draw a rotating cross/plus pattern int center_x = x + 10; int center_y = y + 10; // Clear area first for (int cx = -8; cx <= 8; cx++) { for (int cy = -8; cy <= 8; cy++) { if (center_x + cx >= 0 && center_y + cy >= 0) { canvas->SetPixel(center_x + cx, center_y + cy, 0, 0, 0); } } } // Draw rotating lines based on frame - faster animation if (frame == 0) { // Vertical line for (int i = -6; i <= 6; i++) { canvas->SetPixel(center_x, center_y + i, icon_color.r, icon_color.g, icon_color.b); canvas->SetPixel(center_x + 1, center_y + i, icon_color.r, icon_color.g, icon_color.b); } } else { // frame == 1 // Horizontal line for (int i = -6; i <= 6; i++) { canvas->SetPixel(center_x + i, center_y, icon_color.r, icon_color.g, icon_color.b); canvas->SetPixel(center_x + i, center_y + 1, icon_color.r, icon_color.g, icon_color.b); } } } else if (status == "disconnected" || status == "error") { icon_color = rgb_matrix::Color(255, 0, 0); // Red // Draw an X for (int i = 0; i < 12; i++) { canvas->SetPixel(x + 4 + i, y + 4 + i, icon_color.r, icon_color.g, icon_color.b); canvas->SetPixel(x + 4 + i, y + 16 - i, icon_color.r, icon_color.g, icon_color.b); } } else { icon_color = rgb_matrix::Color(128, 128, 128); // Gray for unknown // Draw a question mark // Simplified question mark for (int i = 0; i < 8; i++) { canvas->SetPixel(x + 6 + i, y + 4, icon_color.r, icon_color.g, icon_color.b); canvas->SetPixel(x + 14, y + 5 + i/2, icon_color.r, icon_color.g, icon_color.b); } canvas->SetPixel(x + 10, y + 15, icon_color.r, icon_color.g, icon_color.b); canvas->SetPixel(x + 11, y + 15, icon_color.r, icon_color.g, icon_color.b); } } // Function to draw the entire network status screen (4G + WiFi) void draw_network_screen(Canvas* canvas, const std::string& network_status, int signal_quality, const std::string& wifi_status) { rgb_matrix::Color white(255, 255, 255); rgb_matrix::Color cyan(0, 255, 255); rgb_matrix::Color bg_color(0, 0, 0); rgb_matrix::Font title_font, value_font, small_font; // Load fonts - try multiple font paths bool fonts_loaded = false; // Try the fonts from your working sensor display if (title_font.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/6x9.bdf") && value_font.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/6x9.bdf") && small_font.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/6x9.bdf")) { fonts_loaded = true; std::cout << "Loaded fonts successfully (6x9)" << std::endl; } // Fallback: try alternative font names else if (title_font.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/9x18B.bdf") && value_font.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/6x9.bdf") && small_font.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/4x6.bdf")) { fonts_loaded = true; std::cout << "Loaded fonts successfully (mixed)" << std::endl; } if (!fonts_loaded) { std::cerr << "Error loading fonts! Check font paths:" << std::endl; std::cerr << " Looking for: /var/www/moduleair_pro_4g/matrix/fonts/6x9.bdf" << std::endl; std::cerr << " Looking for: /var/www/moduleair_pro_4g/matrix/fonts/9x18B.bdf" << std::endl; std::cerr << " Looking for: /var/www/moduleair_pro_4g/matrix/fonts/4x6.bdf" << std::endl; // Use a simple text-based display instead rgb_matrix::Color white(255, 255, 255); rgb_matrix::Color green(0, 255, 0); rgb_matrix::Color red(255, 0, 0); rgb_matrix::Color bg_color(0, 0, 0); // Draw basic status without fonts canvas->Clear(); // Draw simple 4G status indicators using pixels if (network_status == "connected") { // Draw green rectangle for 4G for (int x = 10; x < 30; x++) { for (int y = 10; y < 20; y++) { canvas->SetPixel(x, y, 0, 255, 0); } } } else { // Draw red rectangle for 4G for (int x = 10; x < 30; x++) { for (int y = 10; y < 20; y++) { canvas->SetPixel(x, y, 255, 0, 0); } } } // Draw simple WiFi status indicators using pixels if (wifi_status == "connected") { // Draw green rectangle for WiFi for (int x = 35; x < 55; x++) { for (int y = 10; y < 20; y++) { canvas->SetPixel(x, y, 0, 255, 0); } } } else if (wifi_status == "hotspot") { // Draw orange rectangle for WiFi hotspot for (int x = 35; x < 55; x++) { for (int y = 10; y < 20; y++) { canvas->SetPixel(x, y, 255, 165, 0); } } } else { // Draw red rectangle for WiFi disconnected/unknown for (int x = 35; x < 55; x++) { for (int y = 10; y < 20; y++) { canvas->SetPixel(x, y, 255, 0, 0); } } } // Only draw signal bars if 4G connected if (network_status == "connected") { draw_signal_bars(canvas, 70, 30, signal_quality); } std::cout << "Using fallback display (no fonts)" << std::endl; return; } // Clear screen canvas->Clear(); // Draw title rgb_matrix::DrawText(canvas, title_font, 2, title_font.baseline() + 2, cyan, &bg_color, "NETWORK STATUS", 0); // Draw WiFi connection status section (moved to first) int wifi_y = 20; rgb_matrix::DrawText(canvas, value_font, 2, wifi_y, white, &bg_color, "WiFi:", 0); // Draw WiFi status text rgb_matrix::Color wifi_color; std::string wifi_text = wifi_status; std::transform(wifi_text.begin(), wifi_text.end(), wifi_text.begin(), ::toupper); if (wifi_status == "connected") { wifi_color = rgb_matrix::Color(0, 255, 0); // Green } else if (wifi_status == "hotspot") { wifi_color = rgb_matrix::Color(255, 165, 0); // Orange wifi_text = "HOTSPOT"; } else if (wifi_status == "disconnected") { wifi_color = rgb_matrix::Color(255, 0, 0); // Red } else { wifi_color = rgb_matrix::Color(128, 128, 128); // Gray wifi_text = "UNKNOWN"; } rgb_matrix::DrawText(canvas, value_font, 35, wifi_y, wifi_color, &bg_color, wifi_text.c_str(), 0); // Draw 4G connection status section (moved to second) int status_y = 30; rgb_matrix::DrawText(canvas, value_font, 2, status_y, white, &bg_color, "4G:", 0); // Draw 4G status text rgb_matrix::Color status_color; std::string status_text = network_status; std::transform(status_text.begin(), status_text.end(), status_text.begin(), ::toupper); if (network_status == "connected") { status_color = rgb_matrix::Color(0, 255, 0); // Green } else if (network_status == "connecting") { status_color = rgb_matrix::Color(255, 255, 0); // Yellow } else if (network_status == "booting") { status_color = rgb_matrix::Color(255, 255, 0); // Yellow status_text = "BOOTING"; } else if (network_status == "disconnected" || network_status == "error") { status_color = rgb_matrix::Color(255, 0, 0); // Red } else { status_color = rgb_matrix::Color(128, 128, 128); // Gray status_text = "UNKNOWN"; } rgb_matrix::DrawText(canvas, value_font, 25, status_y, status_color, &bg_color, status_text.c_str(), 0); // Only show 4G signal section if 4G connected (NOT for booting, disconnected, or error) if (network_status == "connected") { // Draw 4G signal strength section (moved higher to prevent truncation) int signal_y = 42; rgb_matrix::DrawText(canvas, value_font, 2, signal_y, white, &bg_color, "4G Signal:", 0); // Draw signal bars draw_signal_bars(canvas, 65, signal_y - 2, signal_quality); // Draw signal value with safe spacing from bottom edge if (signal_quality != -999) { std::stringstream ss; ss << "RSSI: " << signal_quality; rgb_matrix::DrawText(canvas, small_font, 2, signal_y + 8, white, &bg_color, ss.str().c_str(), 0); // Draw signal quality text based on RSSI std::string quality_text; rgb_matrix::Color quality_color; if (signal_quality >= 20) { quality_text = "EXCELLENT"; quality_color = rgb_matrix::Color(0, 255, 0); } else if (signal_quality >= 15) { quality_text = "GOOD"; quality_color = rgb_matrix::Color(0, 255, 0); } else if (signal_quality >= 10) { quality_text = "FAIR"; quality_color = rgb_matrix::Color(255, 255, 0); } else if (signal_quality >= 5) { quality_text = "POOR"; quality_color = rgb_matrix::Color(255, 165, 0); } else if (signal_quality >= 1) { quality_text = "VERY POOR"; quality_color = rgb_matrix::Color(255, 0, 0); } else { quality_text = "NO SIGNAL"; quality_color = rgb_matrix::Color(255, 0, 0); } // Position quality text on the right side with safe spacing rgb_matrix::DrawText(canvas, small_font, 70, signal_y + 8, quality_color, &bg_color, quality_text.c_str(), 0); } else { rgb_matrix::DrawText(canvas, small_font, 2, signal_y + 8, rgb_matrix::Color(128, 128, 128), &bg_color, "NO DATA", 0); } } else { // Clear the 4G signal area completely for all non-connected states for (int clear_x = 0; clear_x < 128; clear_x++) { for (int clear_y = 37; clear_y < 64; clear_y++) { canvas->SetPixel(clear_x, clear_y, 0, 0, 0); } } // Show appropriate message based on 4G status (safe positioning) int msg_y = 42; int msg_y_second_line = 52; if (network_status == "booting") { rgb_matrix::DrawText(canvas, value_font, 2, msg_y, rgb_matrix::Color(255, 255, 0), &bg_color, "4G: Initializing...", 0); } else if (network_status == "disconnected") { rgb_matrix::DrawText(canvas, value_font, 2, msg_y, rgb_matrix::Color(255, 0, 0), &bg_color, "4G: Connection lost", 0); rgb_matrix::DrawText(canvas, value_font, 2, msg_y_second_line, rgb_matrix::Color(255, 0, 0), &bg_color, " Try reconnect", 0); } else if (network_status == "error") { rgb_matrix::DrawText(canvas, value_font, 2, msg_y, rgb_matrix::Color(255, 0, 0), &bg_color, "4G: Modem error", 0); rgb_matrix::DrawText(canvas, value_font, 2, msg_y_second_line, rgb_matrix::Color(255, 0, 0), &bg_color, " Try reconnect", 0); } else if (network_status == "connecting") { rgb_matrix::DrawText(canvas, value_font, 2, msg_y, rgb_matrix::Color(255, 255, 0), &bg_color, "4G: Connecting...", 0); } } // Draw timestamp auto now = std::chrono::system_clock::now(); auto time_t = std::chrono::system_clock::to_time_t(now); auto tm = *std::localtime(&time_t); std::stringstream time_ss; time_ss << std::put_time(&tm, "%H:%M:%S"); rgb_matrix::DrawText(canvas, small_font, 2, 60, rgb_matrix::Color(100, 100, 100), &bg_color, ("Updated: " + time_ss.str()).c_str(), 0); animation_frame++; } int main(int argc, char *argv[]) { log("BLUE", "Network Status Display started"); // Handle signals for graceful exit signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); // Initialize database connection sqlite3* db; std::cout << "Opening SQLite database at " << DB_PATH << std::endl; int rc = sqlite3_open(DB_PATH.c_str(), &db); if (rc) { std::cerr << "Error opening SQLite database: " << sqlite3_errmsg(db) << std::endl; sqlite3_close(db); return 1; } // Initialize LED matrix log("BLUE", "Initializing LED matrix..."); RGBMatrix::Options defaults; defaults.hardware_mapping = "moduleair_pinout"; defaults.rows = 64; defaults.cols = 128; defaults.chain_length = 1; defaults.parallel = 1; defaults.row_address_type = 3; defaults.show_refresh_rate = false; defaults.brightness = 100; defaults.pwm_bits = 1; defaults.panel_type = "FM6126A"; defaults.disable_hardware_pulsing = false; rgb_matrix::RuntimeOptions runtime_opt; runtime_opt.gpio_slowdown = 4; runtime_opt.daemon = 0; runtime_opt.drop_privileges = 0; Canvas *canvas = RGBMatrix::CreateFromOptions(defaults, runtime_opt); if (canvas == NULL) { std::cerr << "Error creating LED matrix canvas" << std::endl; sqlite3_close(db); return 1; } log("GREEN", "LED matrix initialized successfully"); // Main loop log("BLUE", "Starting network status display loop"); while (running) { std::string network_status; int signal_quality; std::string wifi_status; // Get 4G status from database bool data_success = get_4g_status(db, network_status, signal_quality); if (!data_success) { std::cerr << "Error retrieving 4G data from database" << std::endl; network_status = "error"; signal_quality = -999; } // Get WiFi status from database bool wifi_success = get_wifi_status(db, wifi_status); if (!wifi_success) { std::cerr << "Error retrieving WiFi data from database" << std::endl; wifi_status = "unknown"; } // Draw the screen draw_network_screen(canvas, network_status, signal_quality, wifi_status); // Sleep before next update std::cout << "Update complete, sleeping for 5 seconds..." << std::endl; for (int i = 0; i < 5 && running; i++) { sleep(1); // Sleep in 1-second increments for responsive exit } } // Clean up std::cout << "Program terminating, cleaning up..." << std::endl; canvas->Clear(); delete canvas; sqlite3_close(db); std::cout << "Network Status Display terminated" << std::endl; return 0; }