update
This commit is contained in:
BIN
matrix/screenSensors/displayAll4_v1
Normal file
BIN
matrix/screenSensors/displayAll4_v1
Normal file
Binary file not shown.
551
matrix/screenSensors/displayAll4_v1.cc
Normal file
551
matrix/screenSensors/displayAll4_v1.cc
Normal file
@@ -0,0 +1,551 @@
|
||||
/*
|
||||
__ __ _ _____ ____ _____ __
|
||||
| \/ | / \|_ _| _ \|_ _\ \/ /
|
||||
| |\/| | / _ \ | | | |_) || | \ /
|
||||
| | | |/ ___ \| | | _ < | | / \
|
||||
|_| |_/_/ \_\_| |_| \_\___/_/\_\
|
||||
|
||||
|
||||
Script to launch screens to display compounds
|
||||
Get values from SQLite database:
|
||||
- NextPM data from data_NPM table
|
||||
- CO2 data from data_MHZ19 or data_CO2 table
|
||||
- Additional sensors as needed
|
||||
|
||||
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/screenSensors/displayAll4_v1.cc -o /var/www/moduleair_pro_4g/matrix/screenSensors/displayAll4_v1 -lrgbmatrix -lsqlite3
|
||||
|
||||
Pour lancer:
|
||||
sudo /var/www/moduleair_pro_4g/matrix/screenSensors/displayAll4_v1
|
||||
*/
|
||||
|
||||
#include "led-matrix.h"
|
||||
#include "graphics.h"
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <signal.h>
|
||||
#include <atomic>
|
||||
#include <sqlite3.h>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
|
||||
using rgb_matrix::RGBMatrix;
|
||||
using rgb_matrix::Canvas;
|
||||
|
||||
std::atomic<bool> running(true);
|
||||
|
||||
// Path to the SQLite database
|
||||
const std::string DB_PATH = "/var/www/moduleair_pro_4g/sqlite/sensors.db";
|
||||
|
||||
void signal_handler(int signum) {
|
||||
running = false;
|
||||
}
|
||||
|
||||
// Helper function to get current time as string for logging
|
||||
std::string get_current_time() {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
std::time_t now_time = std::chrono::system_clock::to_time_t(now);
|
||||
std::stringstream ss;
|
||||
ss << std::put_time(std::localtime(&now_time), "%Y-%m-%d %H:%M:%S");
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// Function to retrieve latest NPM data from the database
|
||||
bool get_npm_data(sqlite3* db, float& pm10, float& pm25, float& pm1) {
|
||||
sqlite3_stmt* stmt;
|
||||
bool success = false;
|
||||
|
||||
std::cout << get_current_time() << " - Querying NPM data from database..." << std::endl;
|
||||
|
||||
// First, check if the table exists
|
||||
const char* table_check = "SELECT name FROM sqlite_master WHERE type='table' AND name='data_NPM';";
|
||||
if (sqlite3_prepare_v2(db, table_check, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
std::cerr << "SQL error checking table: " << sqlite3_errmsg(db) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool table_exists = false;
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
table_exists = true;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
if (!table_exists) {
|
||||
std::cerr << "Error: data_NPM table does not exist" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Query to get the average of the last 6 NPM measurements
|
||||
const char* query = "SELECT AVG(PM10), AVG(PM25), AVG(PM1) FROM data_NPM ORDER BY rowid DESC LIMIT 6";
|
||||
|
||||
if (sqlite3_prepare_v2(db, query, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
std::cerr << "SQL error preparing query: " << sqlite3_errmsg(db) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
pm10 = sqlite3_column_double(stmt, 0);
|
||||
pm25 = sqlite3_column_double(stmt, 1);
|
||||
pm1 = sqlite3_column_double(stmt, 2);
|
||||
|
||||
std::cout << " Retrieved NPM values - PM10: " << pm10
|
||||
<< ", PM2.5: " << pm25
|
||||
<< ", PM1: " << pm1 << std::endl;
|
||||
|
||||
success = true;
|
||||
} else {
|
||||
std::cerr << " No NPM data found in database" << std::endl;
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
return success;
|
||||
}
|
||||
|
||||
// Function to retrieve latest CO2 data from the database
|
||||
bool get_co2_data(sqlite3* db, float& co2) {
|
||||
sqlite3_stmt* stmt;
|
||||
bool success = false;
|
||||
|
||||
std::cout << get_current_time() << " - Querying CO2 data from database..." << std::endl;
|
||||
|
||||
// Try data_CO2 table directly
|
||||
const char* query_co2 = "SELECT CO2 FROM data_CO2 ORDER BY rowid DESC LIMIT 1";
|
||||
|
||||
if (sqlite3_prepare_v2(db, query_co2, -1, &stmt, NULL) == SQLITE_OK) {
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
co2 = sqlite3_column_double(stmt, 0);
|
||||
std::cout << " Retrieved CO2 value from data_CO2: " << co2 << " ppm" << std::endl;
|
||||
success = true;
|
||||
} else {
|
||||
std::cout << " No data found in data_CO2 table" << std::endl;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
} else {
|
||||
std::cerr << " Error preparing CO2 query: " << sqlite3_errmsg(db) << std::endl;
|
||||
|
||||
// Check if table exists
|
||||
const char* table_check = "SELECT name FROM sqlite_master WHERE type='table' AND name='data_CO2';";
|
||||
if (sqlite3_prepare_v2(db, table_check, -1, &stmt, NULL) == SQLITE_OK) {
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
std::cout << " data_CO2 table exists but query failed" << std::endl;
|
||||
} else {
|
||||
std::cout << " data_CO2 table does not exist in database" << std::endl;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Store previous values to check for changes
|
||||
struct SensorData {
|
||||
float pm10 = 0, pm25 = 0, pm1 = 0, co2 = 0;
|
||||
std::string pm10_str, pm25_str, pm1_str, co2_str;
|
||||
std::string pm10_status, pm25_status, pm1_status, co2_status;
|
||||
rgb_matrix::Color pm10_color, pm25_color, pm1_color, co2_color;
|
||||
};
|
||||
|
||||
// Initial screen setup - draw all static elements
|
||||
void setup_screen(Canvas *canvas) {
|
||||
std::cout << get_current_time() << " - Setting up initial screen layout..." << std::endl;
|
||||
canvas->Clear();
|
||||
|
||||
rgb_matrix::Color myCYAN(0, 255, 255);
|
||||
rgb_matrix::Color bg_color(0, 0, 0);
|
||||
rgb_matrix::Font font1;
|
||||
|
||||
if (!font1.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/6x9.bdf")) {
|
||||
std::cerr << "Error loading font!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
int letter_spacing = 0;
|
||||
int x, y1;
|
||||
|
||||
// Draw static labels for PM10
|
||||
x = 0;
|
||||
y1 = font1.baseline() - 1;
|
||||
rgb_matrix::DrawText(canvas, font1, x, y1, myCYAN, &bg_color, "PM10 µg/m³", letter_spacing);
|
||||
std::cout << " Drew PM10 label" << std::endl;
|
||||
|
||||
// Draw static labels for PM2.5
|
||||
x = 64;
|
||||
rgb_matrix::DrawText(canvas, font1, x, y1, myCYAN, &bg_color, "PM2.5 µg/m³", letter_spacing);
|
||||
std::cout << " Drew PM2.5 label" << std::endl;
|
||||
|
||||
// Draw static labels for PM1
|
||||
x = 0;
|
||||
y1 += 33;
|
||||
rgb_matrix::DrawText(canvas, font1, x, y1, myCYAN, &bg_color, "PM1 µg/m³", letter_spacing);
|
||||
std::cout << " Drew PM1 label" << std::endl;
|
||||
|
||||
// Draw static labels for CO2
|
||||
x = 64;
|
||||
rgb_matrix::DrawText(canvas, font1, x, y1, myCYAN, &bg_color, "CO₂ ppm", letter_spacing);
|
||||
std::cout << " Drew CO2 label" << std::endl;
|
||||
}
|
||||
|
||||
// Function to update only the values and status messages on the screen
|
||||
void update_screen_values(Canvas *canvas, SensorData& prevData, float pm10, float pm25, float pm1, float co2) {
|
||||
std::cout << get_current_time() << " - Updating screen values..." << std::endl;
|
||||
|
||||
rgb_matrix::Color myWHITE(255, 255, 255);
|
||||
rgb_matrix::Color myGREEN(0, 255, 0); // Good
|
||||
rgb_matrix::Color myYELLOW(255, 255, 0); // Moderate
|
||||
rgb_matrix::Color myORANGE(255, 165, 0); // Degraded
|
||||
rgb_matrix::Color myRED(255, 0, 0); // Bad
|
||||
rgb_matrix::Color bg_color(0, 0, 0);
|
||||
|
||||
rgb_matrix::Font font1;
|
||||
rgb_matrix::Font font2;
|
||||
|
||||
if (!font1.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/6x9.bdf")) {
|
||||
std::cerr << "Error loading font1!" << std::endl;
|
||||
return;
|
||||
}
|
||||
if (!font2.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/9x18B.bdf")) {
|
||||
std::cerr << "Error loading font2!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
int letter_spacing = 0;
|
||||
int x, y1, y2, y3;
|
||||
|
||||
// Convert float values to strings with 1 decimal place
|
||||
std::stringstream ss_pm10, ss_pm25, ss_pm1, ss_co2;
|
||||
ss_pm10 << std::fixed << std::setprecision(1) << pm10;
|
||||
ss_pm25 << std::fixed << std::setprecision(1) << pm25;
|
||||
ss_pm1 << std::fixed << std::setprecision(1) << pm1;
|
||||
ss_co2 << std::fixed << std::setprecision(0) << co2;
|
||||
|
||||
std::string str_pm10 = ss_pm10.str();
|
||||
std::string str_pm25 = ss_pm25.str();
|
||||
std::string str_pm1 = ss_pm1.str();
|
||||
std::string str_co2 = ss_co2.str();
|
||||
|
||||
// Define coordinates for values and status messages
|
||||
x = 0;
|
||||
y1 = font1.baseline() - 1;
|
||||
y2 = y1 + font2.baseline() + 1;
|
||||
y3 = y1 + y2 + 4;
|
||||
|
||||
// Update PM10 value and status if changed
|
||||
if (str_pm10 != prevData.pm10_str) {
|
||||
std::cout << " Updating PM10 value from " << prevData.pm10_str << " to " << str_pm10 << std::endl;
|
||||
// Clear previous value area
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y1 + 1; j < y2 + 5; j++) {
|
||||
canvas->SetPixel(x + i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new value
|
||||
rgb_matrix::DrawText(canvas, font2, x, y2, myWHITE, &bg_color, str_pm10.c_str(), letter_spacing);
|
||||
prevData.pm10_str = str_pm10;
|
||||
}
|
||||
|
||||
// Determine PM10 status
|
||||
std::string pm10_status;
|
||||
rgb_matrix::Color pm10_color;
|
||||
if (pm10 < 15) {
|
||||
pm10_status = "BON";
|
||||
pm10_color = myGREEN;
|
||||
} else if (pm10 >= 15 && pm10 < 30) {
|
||||
pm10_status = "MOYEN";
|
||||
pm10_color = myYELLOW;
|
||||
} else if (pm10 >= 30 && pm10 < 75) {
|
||||
pm10_status = "DEGRADE";
|
||||
pm10_color = myORANGE;
|
||||
} else {
|
||||
pm10_status = "MAUVAIS";
|
||||
pm10_color = myRED;
|
||||
}
|
||||
|
||||
// Update PM10 status if changed
|
||||
if (pm10_status != prevData.pm10_status || pm10_color.r != prevData.pm10_color.r ||
|
||||
pm10_color.g != prevData.pm10_color.g || pm10_color.b != prevData.pm10_color.b) {
|
||||
std::cout << " Updating PM10 status to " << pm10_status << std::endl;
|
||||
// Clear previous status area
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y2 + 6; j < y3 + 10; j++) {
|
||||
canvas->SetPixel(x + i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new status
|
||||
rgb_matrix::DrawText(canvas, font1, x, y3, pm10_color, &bg_color, pm10_status.c_str(), letter_spacing);
|
||||
prevData.pm10_status = pm10_status;
|
||||
prevData.pm10_color = pm10_color;
|
||||
}
|
||||
|
||||
// Update PM2.5 value and status
|
||||
x = 64;
|
||||
if (str_pm25 != prevData.pm25_str) {
|
||||
std::cout << " Updating PM2.5 value from " << prevData.pm25_str << " to " << str_pm25 << std::endl;
|
||||
// Clear previous value area
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y1 + 1; j < y2 + 5; j++) {
|
||||
canvas->SetPixel(x + i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new value
|
||||
rgb_matrix::DrawText(canvas, font2, x, y2, myWHITE, &bg_color, str_pm25.c_str(), letter_spacing);
|
||||
prevData.pm25_str = str_pm25;
|
||||
}
|
||||
|
||||
// Determine PM2.5 status
|
||||
std::string pm25_status;
|
||||
rgb_matrix::Color pm25_color;
|
||||
if (pm25 < 10) {
|
||||
pm25_status = "BON";
|
||||
pm25_color = myGREEN;
|
||||
} else if (pm25 >= 10 && pm25 < 20) {
|
||||
pm25_status = "MOYEN";
|
||||
pm25_color = myYELLOW;
|
||||
} else if (pm25 >= 20 && pm25 < 50) {
|
||||
pm25_status = "DEGRADE";
|
||||
pm25_color = myORANGE;
|
||||
} else {
|
||||
pm25_status = "MAUVAIS";
|
||||
pm25_color = myRED;
|
||||
}
|
||||
|
||||
// Update PM2.5 status if changed
|
||||
if (pm25_status != prevData.pm25_status || pm25_color.r != prevData.pm25_color.r ||
|
||||
pm25_color.g != prevData.pm25_color.g || pm25_color.b != prevData.pm25_color.b) {
|
||||
std::cout << " Updating PM2.5 status to " << pm25_status << std::endl;
|
||||
// Clear previous status area
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y2 + 6; j < y3 + 10; j++) {
|
||||
canvas->SetPixel(x + i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new status
|
||||
rgb_matrix::DrawText(canvas, font1, x, y3, pm25_color, &bg_color, pm25_status.c_str(), letter_spacing);
|
||||
prevData.pm25_status = pm25_status;
|
||||
prevData.pm25_color = pm25_color;
|
||||
}
|
||||
|
||||
// Update PM1 value and status
|
||||
x = 0;
|
||||
y1 += 33;
|
||||
y2 += 33;
|
||||
y3 += 33;
|
||||
|
||||
if (str_pm1 != prevData.pm1_str) {
|
||||
std::cout << " Updating PM1 value from " << prevData.pm1_str << " to " << str_pm1 << std::endl;
|
||||
// Clear previous value area
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y1 + 1; j < y2 + 5; j++) {
|
||||
canvas->SetPixel(x + i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new value
|
||||
rgb_matrix::DrawText(canvas, font2, x, y2, myWHITE, &bg_color, str_pm1.c_str(), letter_spacing);
|
||||
prevData.pm1_str = str_pm1;
|
||||
}
|
||||
|
||||
// Determine PM1 status
|
||||
std::string pm1_status;
|
||||
rgb_matrix::Color pm1_color;
|
||||
if (pm1 < 10) {
|
||||
pm1_status = "BON";
|
||||
pm1_color = myGREEN;
|
||||
} else if (pm1 >= 10 && pm1 < 20) {
|
||||
pm1_status = "MOYEN";
|
||||
pm1_color = myYELLOW;
|
||||
} else if (pm1 >= 20 && pm1 < 50) {
|
||||
pm1_status = "DEGRADE";
|
||||
pm1_color = myORANGE;
|
||||
} else {
|
||||
pm1_status = "MAUVAIS";
|
||||
pm1_color = myRED;
|
||||
}
|
||||
|
||||
// Update PM1 status if changed
|
||||
if (pm1_status != prevData.pm1_status || pm1_color.r != prevData.pm1_color.r ||
|
||||
pm1_color.g != prevData.pm1_color.g || pm1_color.b != prevData.pm1_color.b) {
|
||||
std::cout << " Updating PM1 status to " << pm1_status << std::endl;
|
||||
// Clear previous status area
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y2 + 6; j < y3 + 10; j++) {
|
||||
canvas->SetPixel(x + i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new status
|
||||
rgb_matrix::DrawText(canvas, font1, x, y3, pm1_color, &bg_color, pm1_status.c_str(), letter_spacing);
|
||||
prevData.pm1_status = pm1_status;
|
||||
prevData.pm1_color = pm1_color;
|
||||
}
|
||||
|
||||
// Update CO2 value and status
|
||||
x = 64;
|
||||
if (str_co2 != prevData.co2_str) {
|
||||
std::cout << " Updating CO2 value from " << prevData.co2_str << " to " << str_co2 << std::endl;
|
||||
// Clear previous value area
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y1 + 1; j < y2 + 5; j++) {
|
||||
canvas->SetPixel(x + i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new value
|
||||
rgb_matrix::DrawText(canvas, font2, x, y2, myWHITE, &bg_color, str_co2.c_str(), letter_spacing);
|
||||
prevData.co2_str = str_co2;
|
||||
}
|
||||
|
||||
// Determine CO2 status
|
||||
std::string co2_status;
|
||||
rgb_matrix::Color co2_color;
|
||||
if (co2 < 800) {
|
||||
co2_status = "BON";
|
||||
co2_color = myGREEN;
|
||||
} else if (co2 >= 800 && co2 < 1500) {
|
||||
co2_status = "AERER SVP";
|
||||
co2_color = myORANGE;
|
||||
} else {
|
||||
co2_status = "AERER VITE";
|
||||
co2_color = myRED;
|
||||
}
|
||||
|
||||
// Update CO2 status if changed
|
||||
if (co2_status != prevData.co2_status || co2_color.r != prevData.co2_color.r ||
|
||||
co2_color.g != prevData.co2_color.g || co2_color.b != prevData.co2_color.b) {
|
||||
std::cout << " Updating CO2 status to " << co2_status << std::endl;
|
||||
// Clear previous status area
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y2 + 6; j < y3 + 10; j++) {
|
||||
canvas->SetPixel(x + i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new status
|
||||
rgb_matrix::DrawText(canvas, font1, x, y3, co2_color, &bg_color, co2_status.c_str(), letter_spacing);
|
||||
prevData.co2_status = co2_status;
|
||||
prevData.co2_color = co2_color;
|
||||
}
|
||||
|
||||
// Update stored values
|
||||
prevData.pm10 = pm10;
|
||||
prevData.pm25 = pm25;
|
||||
prevData.pm1 = pm1;
|
||||
prevData.co2 = co2;
|
||||
}
|
||||
|
||||
// Function to dump database tables for debugging
|
||||
void list_database_tables(sqlite3* db) {
|
||||
sqlite3_stmt* stmt;
|
||||
const char* query = "SELECT name FROM sqlite_master WHERE type='table';";
|
||||
|
||||
std::cout << "====== DATABASE TABLES ======" << std::endl;
|
||||
|
||||
if (sqlite3_prepare_v2(db, query, -1, &stmt, NULL) == SQLITE_OK) {
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
const unsigned char* table_name = sqlite3_column_text(stmt, 0);
|
||||
std::cout << "Table: " << table_name << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Error listing tables: " << sqlite3_errmsg(db) << std::endl;
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
std::cout << "============================" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::cout << "===== Starting ModuleAir Display Program =====" << std::endl;
|
||||
std::cout << get_current_time() << " - Program started" << std::endl;
|
||||
|
||||
// Handle signals for graceful exit
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
|
||||
// Initialize database connection
|
||||
sqlite3* db;
|
||||
std::cout << get_current_time() << " - 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;
|
||||
}
|
||||
|
||||
// List available tables for debugging
|
||||
list_database_tables(db);
|
||||
|
||||
// Initialize LED matrix
|
||||
std::cout << get_current_time() << " - Initializing LED matrix..." << std::endl;
|
||||
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; // Adjust based on your Raspberry Pi model
|
||||
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;
|
||||
}
|
||||
std::cout << get_current_time() << " - LED matrix initialized successfully" << std::endl;
|
||||
|
||||
// Set up the initial screen layout (static elements)
|
||||
setup_screen(canvas);
|
||||
|
||||
// Structure to store previous data values
|
||||
SensorData prevData;
|
||||
|
||||
// Initial sensor values
|
||||
float pm10 = 0, pm25 = 0, pm1 = 0, co2 = 0;
|
||||
|
||||
int update_count = 0;
|
||||
|
||||
// Main loop
|
||||
std::cout << get_current_time() << " - Starting main loop..." << std::endl;
|
||||
while (running) {
|
||||
update_count++;
|
||||
std::cout << "\n" << get_current_time() << " - Update cycle #" << update_count << " started" << std::endl;
|
||||
|
||||
// Get data from database
|
||||
bool npm_success = get_npm_data(db, pm10, pm25, pm1);
|
||||
bool co2_success = get_co2_data(db, co2);
|
||||
|
||||
if (!npm_success) {
|
||||
std::cerr << "Error retrieving NPM data from database" << std::endl;
|
||||
}
|
||||
|
||||
if (!co2_success) {
|
||||
std::cerr << "Error retrieving CO2 data from database" << std::endl;
|
||||
}
|
||||
|
||||
// Update just the values and status messages
|
||||
update_screen_values(canvas, prevData, pm10, pm25, pm1, co2);
|
||||
|
||||
// Sleep before next update
|
||||
std::cout << get_current_time() << " - Update complete, sleeping for 10 seconds..." << std::endl;
|
||||
for (int i = 0; i < 10 && running; i++) {
|
||||
sleep(1); // Sleep in 1-second increments to be more responsive to stop signals
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
std::cout << get_current_time() << " - Program terminating, cleaning up..." << std::endl;
|
||||
canvas->Clear();
|
||||
delete canvas;
|
||||
sqlite3_close(db);
|
||||
std::cout << get_current_time() << " - Program terminated" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
BIN
matrix/screenSensors/displayAll4_v2
Normal file
BIN
matrix/screenSensors/displayAll4_v2
Normal file
Binary file not shown.
570
matrix/screenSensors/displayAll4_v2.cc
Normal file
570
matrix/screenSensors/displayAll4_v2.cc
Normal file
@@ -0,0 +1,570 @@
|
||||
/*
|
||||
__ __ _ _____ ____ _____ __
|
||||
| \/ | / \|_ _| _ \|_ _\ \/ /
|
||||
| |\/| | / _ \ | | | |_) || | \ /
|
||||
| | | |/ ___ \| | | _ < | | / \
|
||||
|_| |_/_/ \_\_| |_| \_\___/_/\_\
|
||||
|
||||
|
||||
Script to launch screens to display compounds
|
||||
Get values from SQLite database:
|
||||
- NextPM data from data_NPM table
|
||||
- CO2 data from data_MHZ19 or data_CO2 table
|
||||
- Additional sensors as needed
|
||||
|
||||
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/screenSensors/displayAll4_v2.cc -o /var/www/moduleair_pro_4g/matrix/screenSensors/displayAll4_v2 -lrgbmatrix -lsqlite3
|
||||
|
||||
Pour lancer:
|
||||
sudo /var/www/moduleair_pro_4g/matrix/screenSensors/displayAll4_v2
|
||||
*/
|
||||
|
||||
#include "led-matrix.h"
|
||||
#include "graphics.h"
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <signal.h>
|
||||
#include <atomic>
|
||||
#include <sqlite3.h>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
|
||||
using rgb_matrix::RGBMatrix;
|
||||
using rgb_matrix::Canvas;
|
||||
|
||||
std::atomic<bool> running(true);
|
||||
|
||||
// Define color codes
|
||||
#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";
|
||||
|
||||
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 retrieve latest NPM data from the database
|
||||
bool get_npm_data(sqlite3* db, float& pm10, float& pm25, float& pm1) {
|
||||
sqlite3_stmt* stmt;
|
||||
bool success = false;
|
||||
|
||||
std::cout << " - Querying latest NPM data from database..." << std::endl;
|
||||
|
||||
// First, check if the table exists
|
||||
const char* table_check = "SELECT name FROM sqlite_master WHERE type='table' AND name='data_NPM';";
|
||||
if (sqlite3_prepare_v2(db, table_check, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
std::cerr << "SQL error checking table: " << sqlite3_errmsg(db) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool table_exists = false;
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
table_exists = true;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
if (!table_exists) {
|
||||
std::cerr << "Error: data_NPM table does not exist" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Query to get the latest NPM measurement
|
||||
const char* query = "SELECT PM10, PM25, PM1 FROM data_NPM ORDER BY rowid DESC LIMIT 1";
|
||||
|
||||
if (sqlite3_prepare_v2(db, query, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
std::cerr << "SQL error preparing query: " << sqlite3_errmsg(db) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
pm10 = sqlite3_column_double(stmt, 0);
|
||||
pm25 = sqlite3_column_double(stmt, 1);
|
||||
pm1 = sqlite3_column_double(stmt, 2);
|
||||
|
||||
std::cout << " Retrieved latest NPM values - PM10: " << pm10
|
||||
<< ", PM2.5: " << pm25
|
||||
<< ", PM1: " << pm1 << std::endl;
|
||||
|
||||
success = true;
|
||||
} else {
|
||||
std::cerr << " No NPM data found in database" << std::endl;
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
return success;
|
||||
}
|
||||
|
||||
// Function to retrieve latest CO2 data from the database
|
||||
bool get_co2_data(sqlite3* db, float& co2) {
|
||||
sqlite3_stmt* stmt;
|
||||
bool success = false;
|
||||
|
||||
std::cout << " - Querying CO2 data from database..." << std::endl;
|
||||
|
||||
// Try data_CO2 table directly
|
||||
const char* query_co2 = "SELECT CO2 FROM data_CO2 ORDER BY rowid DESC LIMIT 1";
|
||||
|
||||
if (sqlite3_prepare_v2(db, query_co2, -1, &stmt, NULL) == SQLITE_OK) {
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
co2 = sqlite3_column_double(stmt, 0);
|
||||
std::cout << " Retrieved CO2 value from data_CO2: " << co2 << " ppm" << std::endl;
|
||||
success = true;
|
||||
} else {
|
||||
std::cout << " No data found in data_CO2 table" << std::endl;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
} else {
|
||||
std::cerr << " Error preparing CO2 query: " << sqlite3_errmsg(db) << std::endl;
|
||||
|
||||
// Check if table exists
|
||||
const char* table_check = "SELECT name FROM sqlite_master WHERE type='table' AND name='data_CO2';";
|
||||
if (sqlite3_prepare_v2(db, table_check, -1, &stmt, NULL) == SQLITE_OK) {
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
std::cout << " data_CO2 table exists but query failed" << std::endl;
|
||||
} else {
|
||||
std::cout << " data_CO2 table does not exist in database" << std::endl;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Store previous values to check for changes
|
||||
struct SensorData {
|
||||
float pm10 = 0, pm25 = 0, pm1 = 0, co2 = 0;
|
||||
std::string pm10_str, pm25_str, pm1_str, co2_str;
|
||||
std::string pm10_status, pm25_status, pm1_status, co2_status;
|
||||
rgb_matrix::Color pm10_color, pm25_color, pm1_color, co2_color;
|
||||
};
|
||||
|
||||
// Initial screen setup - draw all static elements
|
||||
void setup_screen(Canvas *canvas) {
|
||||
std::cout << " - Setting up initial screen layout..." << std::endl;
|
||||
canvas->Clear();
|
||||
|
||||
rgb_matrix::Color myCYAN(0, 255, 255);
|
||||
rgb_matrix::Color bg_color(0, 0, 0);
|
||||
rgb_matrix::Font font1;
|
||||
|
||||
if (!font1.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/6x9.bdf")) {
|
||||
std::cerr << "Error loading font!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
int letter_spacing = 0;
|
||||
|
||||
// Calculate absolute positions for each row
|
||||
// Instead of using relative positions with increments
|
||||
int top_row_y = font1.baseline()-1;
|
||||
int bottom_row_y = 33 + font1.baseline()-1; // Fixed position for second row
|
||||
|
||||
// Draw static labels for top row
|
||||
rgb_matrix::DrawText(canvas, font1, 0, top_row_y, myCYAN, &bg_color, "PM10 µg/m³", letter_spacing);
|
||||
rgb_matrix::DrawText(canvas, font1, 64, top_row_y, myCYAN, &bg_color, "PM2.5 µg/m³", letter_spacing);
|
||||
|
||||
rgb_matrix::DrawText(canvas, font1, 0, bottom_row_y, myCYAN, &bg_color, "PM1 µg/m³", letter_spacing);
|
||||
rgb_matrix::DrawText(canvas, font1, 64, bottom_row_y, myCYAN, &bg_color, "CO₂ ppm", letter_spacing);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Function to update only the values and status messages on the screen
|
||||
void update_screen_values(Canvas *canvas, SensorData& prevData, float pm10, float pm25, float pm1, float co2) {
|
||||
log("BLUE", "Updating screen values...");
|
||||
|
||||
rgb_matrix::Color myWHITE(255, 255, 255);
|
||||
rgb_matrix::Color myGREEN(0, 255, 0); // Good
|
||||
rgb_matrix::Color myYELLOW(255, 255, 0); // Moderate
|
||||
rgb_matrix::Color myORANGE(255, 165, 0); // Degraded
|
||||
rgb_matrix::Color myRED(255, 0, 0); // Bad
|
||||
rgb_matrix::Color bg_color(0, 0, 0);
|
||||
|
||||
rgb_matrix::Font font1;
|
||||
rgb_matrix::Font font2;
|
||||
|
||||
if (!font1.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/6x9.bdf")) {
|
||||
std::cerr << "Error loading font1!" << std::endl;
|
||||
return;
|
||||
}
|
||||
if (!font2.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/9x18B.bdf")) {
|
||||
std::cerr << "Error loading font2!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
int letter_spacing = 0;
|
||||
int x, y1, y2, y3;
|
||||
|
||||
// Convert float values to strings with 1 decimal place
|
||||
std::stringstream ss_pm10, ss_pm25, ss_pm1, ss_co2;
|
||||
ss_pm10 << std::fixed << std::setprecision(1) << pm10;
|
||||
ss_pm25 << std::fixed << std::setprecision(1) << pm25;
|
||||
ss_pm1 << std::fixed << std::setprecision(1) << pm1;
|
||||
ss_co2 << std::fixed << std::setprecision(0) << co2;
|
||||
|
||||
std::string str_pm10 = ss_pm10.str();
|
||||
std::string str_pm25 = ss_pm25.str();
|
||||
std::string str_pm1 = ss_pm1.str();
|
||||
std::string str_co2 = ss_co2.str();
|
||||
|
||||
// Define coordinates for values and status messages
|
||||
x = 0;
|
||||
y1 = font1.baseline() - 1; //ligne tout en haut (bleue PM10 µg/m³ )
|
||||
y2 = y1 + font2.baseline() + 1; //ligne pour les chiffres (blanc bold)
|
||||
y3 = y1 + y2 + 4; //ligne pour les adjectifs (BON, MOYEN, ETC)
|
||||
|
||||
/*
|
||||
____ __ __ _ ___
|
||||
| _ \| \/ / |/ _ \
|
||||
| |_) | |\/| | | | | |
|
||||
| __/| | | | | |_| |
|
||||
|_| |_| |_|_|\___/
|
||||
|
||||
*/
|
||||
|
||||
// Update PM10 value and status if changed
|
||||
if (str_pm10 != prevData.pm10_str) {
|
||||
std::cout << " Updating PM10 value from " << prevData.pm10_str << " to " << str_pm10 << std::endl;
|
||||
// On clear l'espace chiffre blanc
|
||||
for (int i = 0; i < 60; i++) { //axe x (on clear de 0 à 60)
|
||||
for (int j = y1 + 2; j < y2 + 1; j++) { //axe y (on clear de la ligne y1 à y2)
|
||||
canvas->SetPixel(i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new value
|
||||
rgb_matrix::DrawText(canvas, font2, x, y2, myWHITE, &bg_color, str_pm10.c_str(), letter_spacing);
|
||||
prevData.pm10_str = str_pm10;
|
||||
}
|
||||
|
||||
// Determine PM10 status
|
||||
std::string pm10_status;
|
||||
rgb_matrix::Color pm10_color;
|
||||
if (pm10 < 15) {
|
||||
pm10_status = "BON";
|
||||
pm10_color = myGREEN;
|
||||
} else if (pm10 >= 15 && pm10 < 30) {
|
||||
pm10_status = "MOYEN";
|
||||
pm10_color = myYELLOW;
|
||||
} else if (pm10 >= 30 && pm10 < 75) {
|
||||
pm10_status = "DEGRADE";
|
||||
pm10_color = myORANGE;
|
||||
} else {
|
||||
pm10_status = "MAUVAIS";
|
||||
pm10_color = myRED;
|
||||
}
|
||||
|
||||
// Update PM10 status if changed
|
||||
|
||||
std::cout << " Updating PM10 status to " << pm10_status << std::endl;
|
||||
// on clear l'espace texte BON, MOYEN
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y2 + 4; j < y3 + 1; j++) {
|
||||
canvas->SetPixel(x + i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new status
|
||||
rgb_matrix::DrawText(canvas, font1, x, y3, pm10_color, &bg_color, pm10_status.c_str(), letter_spacing);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
____ __ __ ____ ____
|
||||
| _ \| \/ |___ \ | ___|
|
||||
| |_) | |\/| | __) | |___ \
|
||||
| __/| | | |/ __/ _ ___) |
|
||||
|_| |_| |_|_____(_)____/
|
||||
|
||||
*/
|
||||
|
||||
// Update PM2.5 value and status
|
||||
x = 64;
|
||||
|
||||
if (str_pm25 != prevData.pm25_str) {
|
||||
std::cout << " Updating PM2.5 value from " << prevData.pm25_str << " to " << str_pm25 << std::endl;
|
||||
// Clear previous value area
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y1 + 2; j < y2 + 1; j++) {
|
||||
canvas->SetPixel(x + i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new value
|
||||
rgb_matrix::DrawText(canvas, font2, x, y2, myWHITE, &bg_color, str_pm25.c_str(), letter_spacing);
|
||||
prevData.pm25_str = str_pm25;
|
||||
}
|
||||
|
||||
// Determine PM2.5 status
|
||||
std::string pm25_status;
|
||||
rgb_matrix::Color pm25_color;
|
||||
if (pm25 < 10) {
|
||||
pm25_status = "BON";
|
||||
pm25_color = myGREEN;
|
||||
} else if (pm25 >= 10 && pm25 < 20) {
|
||||
pm25_status = "MOYEN";
|
||||
pm25_color = myYELLOW;
|
||||
} else if (pm25 >= 20 && pm25 < 50) {
|
||||
pm25_status = "DEGRADE";
|
||||
pm25_color = myORANGE;
|
||||
} else {
|
||||
pm25_status = "MAUVAIS";
|
||||
pm25_color = myRED;
|
||||
}
|
||||
|
||||
// Update PM2.5 status
|
||||
|
||||
std::cout << " Updating PM2.5 status to " << pm25_status << std::endl;
|
||||
// Clear previous status area
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y2 + 2; j < y3 + 1; j++) {
|
||||
canvas->SetPixel(x + i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new status
|
||||
rgb_matrix::DrawText(canvas, font1, x, y3, pm25_color, &bg_color, pm25_status.c_str(), letter_spacing);
|
||||
|
||||
|
||||
/*
|
||||
____ __ __ _
|
||||
| _ \| \/ / |
|
||||
| |_) | |\/| | |
|
||||
| __/| | | | |
|
||||
|_| |_| |_|_|
|
||||
|
||||
*/
|
||||
|
||||
// Update PM1 value and status
|
||||
x = 0;
|
||||
y1 += 34;
|
||||
y2 += 34;
|
||||
y3 += 33;
|
||||
|
||||
if (str_pm1 != prevData.pm1_str) {
|
||||
std::cout << " Updating PM1 value from " << prevData.pm1_str << " to " << str_pm1 << std::endl;
|
||||
// Clear previous value area
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y1 + 3; j < y2 + 1; j++) {
|
||||
canvas->SetPixel(x + i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new value
|
||||
rgb_matrix::DrawText(canvas, font2, x, y2, myWHITE, &bg_color, str_pm1.c_str(), letter_spacing);
|
||||
prevData.pm1_str = str_pm1;
|
||||
}
|
||||
|
||||
// Determine PM1 status
|
||||
std::string pm1_status;
|
||||
rgb_matrix::Color pm1_color;
|
||||
if (pm1 < 10) {
|
||||
pm1_status = "BON";
|
||||
pm1_color = myGREEN;
|
||||
} else if (pm1 >= 10 && pm1 < 20) {
|
||||
pm1_status = "MOYEN";
|
||||
pm1_color = myYELLOW;
|
||||
} else if (pm1 >= 20 && pm1 < 50) {
|
||||
pm1_status = "DEGRADE";
|
||||
pm1_color = myORANGE;
|
||||
} else {
|
||||
pm1_status = "MAUVAIS";
|
||||
pm1_color = myRED;
|
||||
}
|
||||
|
||||
// Update
|
||||
|
||||
std::cout << " Updating PM1 status to " << pm1_status << std::endl;
|
||||
// Clear previous status area
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y2 + 3; j < y3 + 1; j++) {
|
||||
canvas->SetPixel(x + i, j, 255, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new status
|
||||
rgb_matrix::DrawText(canvas, font1, x, y3, pm1_color, &bg_color, pm1_status.c_str(), letter_spacing);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
____ ___ ____
|
||||
/ ___/ _ \___ \
|
||||
| | | | | |__) |
|
||||
| |__| |_| / __/
|
||||
\____\___/_____|
|
||||
|
||||
*/
|
||||
// Update CO2 value and status
|
||||
x = 64;
|
||||
if (str_co2 != prevData.co2_str) {
|
||||
std::cout << " Updating CO2 value from " << prevData.co2_str << " to " << str_co2 << std::endl;
|
||||
// Clear previous value area
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y1 + 3; j < y2 + 1; j++) {
|
||||
canvas->SetPixel(x + i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new value
|
||||
rgb_matrix::DrawText(canvas, font2, x, y2, myWHITE, &bg_color, str_co2.c_str(), letter_spacing);
|
||||
prevData.co2_str = str_co2;
|
||||
}
|
||||
|
||||
// Determine CO2 status
|
||||
std::string co2_status;
|
||||
rgb_matrix::Color co2_color;
|
||||
if (co2 < 800) {
|
||||
co2_status = "BON";
|
||||
co2_color = myGREEN;
|
||||
} else if (co2 >= 800 && co2 < 1500) {
|
||||
co2_status = "AERER SVP";
|
||||
co2_color = myORANGE;
|
||||
} else {
|
||||
co2_status = "AERER VITE";
|
||||
co2_color = myRED;
|
||||
}
|
||||
|
||||
// Update CO2 status
|
||||
|
||||
std::cout << " Updating CO2 status to " << co2_status << std::endl;
|
||||
// Clear previous status area
|
||||
for (int i = 0; i < 60; i++) {
|
||||
for (int j = y2 + 4; j < y3 + 1; j++) {
|
||||
canvas->SetPixel(x + i, j, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// Draw new status
|
||||
rgb_matrix::DrawText(canvas, font1, x, y3, co2_color, &bg_color, co2_status.c_str(), letter_spacing);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
__ __ _ ___ _ _
|
||||
| \/ | / \ |_ _| \ | |
|
||||
| |\/| | / _ \ | || \| |
|
||||
| | | |/ ___ \ | || |\ |
|
||||
|_| |_/_/ \_\___|_| \_|
|
||||
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
log("BLUE", "Program 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; // Adjust based on your Raspberry Pi model
|
||||
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");
|
||||
|
||||
|
||||
// Set up the initial screen layout (static elements)
|
||||
setup_screen(canvas);
|
||||
|
||||
// Structure to store previous data values
|
||||
SensorData prevData;
|
||||
|
||||
// Initial sensor values
|
||||
float pm10 = 0, pm25 = 0, pm1 = 0, co2 = 0;
|
||||
|
||||
|
||||
/*
|
||||
_ ___ ___ ____
|
||||
| | / _ \ / _ \| _ \
|
||||
| | | | | | | | | |_) |
|
||||
| |__| |_| | |_| | __/
|
||||
|_____\___/ \___/|_|
|
||||
|
||||
*/
|
||||
log("BLUE", "Starting main loop");
|
||||
while (running) {
|
||||
|
||||
// Get data from database
|
||||
bool npm_success = get_npm_data(db, pm10, pm25, pm1);
|
||||
bool co2_success = get_co2_data(db, co2);
|
||||
|
||||
if (!npm_success) {
|
||||
std::cerr << "Error retrieving NPM data from database" << std::endl;
|
||||
}
|
||||
|
||||
if (!co2_success) {
|
||||
std::cerr << "Error retrieving CO2 data from database" << std::endl;
|
||||
}
|
||||
|
||||
// Update just the values and status messages
|
||||
update_screen_values(canvas, prevData, pm10, pm25, pm1, co2);
|
||||
|
||||
// Sleep before next update
|
||||
std::cout << " - Update complete, sleeping for 10 seconds..." << std::endl;
|
||||
for (int i = 0; i < 10 && running; i++) {
|
||||
sleep(1); // Sleep in 1-second increments to be more responsive to stop signals
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
std::cout << " - Program terminating, cleaning up..." << std::endl;
|
||||
canvas->Clear();
|
||||
delete canvas;
|
||||
sqlite3_close(db);
|
||||
std::cout << " - Program terminated" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +1,11 @@
|
||||
/*
|
||||
__ __ _ _____ ____ _____ __
|
||||
| \/ | / \|_ _| _ \|_ _\ \/ /
|
||||
| |\/| | / _ \ | | | |_) || | \ /
|
||||
| | | |/ ___ \| | | _ < | | / \
|
||||
|_| |_/_/ \_\_| |_| \_\___/_/\_\
|
||||
|
||||
|
||||
Script to launch screens to display compounds
|
||||
Get values from
|
||||
NextPM -> "/var/www/moduleair_pro_4g/matrix/input_NPM.txt"
|
||||
@@ -8,7 +15,12 @@ Sensirion ->
|
||||
sudo /var/www/moduleair_pro_4g/matrix/screen_sensors_loop
|
||||
|
||||
Pour compiler:
|
||||
g++ -Iinclude -Llib screen_sensors_loop.cc -o screen_sensors_loop -lrgbmatrix
|
||||
g++ -I/var/www/moduleair_pro_4g/matrix/include -L/var/www/moduleair_pro_4g/matrix/lib /var/www/moduleair_pro_4g/matrix/screenSensor/test_image.cc -o /var/www/moduleair_pro_4g/matrix/screenSensor/test_image.cc -lrgbmatrix
|
||||
|
||||
pour lancer:
|
||||
|
||||
sudo /var/www/moduleair_pro_4g/matrix/screenSensors/screen_sensors_loop
|
||||
|
||||
*/
|
||||
|
||||
#include "led-matrix.h"
|
||||
@@ -30,7 +42,7 @@ void signal_handler(int signum) {
|
||||
}
|
||||
|
||||
|
||||
//message d'accueil
|
||||
//message d'accueil (OLD)
|
||||
void draw_welcome_screen(Canvas *canvas) {
|
||||
canvas->Clear();
|
||||
|
||||
@@ -171,7 +183,7 @@ int main(int argc, char *argv[]) {
|
||||
return 1;
|
||||
|
||||
// Display welcome screen once
|
||||
draw_welcome_screen(canvas);
|
||||
//draw_welcome_screen(canvas);
|
||||
|
||||
// Initialize variables for main loop
|
||||
std::string input_file_NPM = "/var/www/moduleair_pro_4g/matrix/input_NPM.txt";
|
||||
|
||||
Reference in New Issue
Block a user