Sistema de Integração em Tempo Real para Monitoramento Industrial
industrial-monitoring-system/
├── CMakeLists.txt # Arquivo CMake de build de nível superior
├── README.md # Descrição do projeto e instruções
├── LICENSE # Licença do projeto (ex: MIT, Apache 2.0)
├── .gitignore # Arquivos e diretórios para ignorar no Git
├── src/ # Código-fonte para o backend C++
│ ├── database/ # Código relacionado ao banco de dados
│ │ ├── DatabaseManager.h
│ │ ├── DatabaseManager.cpp
│ │ └── ... (outros arquivos de banco de dados, se necessário)
│ ├── sensors/ # Geração e manipulação de dados de sensores
│ │ ├── RealTimeDataGenerator.h
│ │ ├── RealTimeDataGenerator.cpp
│ │ └── ...
│ ├── monitoring/ # Componentes de monitoramento de console
│ │ ├── DataMonitor.h
│ │ ├── DataMonitor.cpp
│ │ └── ...
│ ├── simulation/ # Componentes de simulação de consulta
│ │ ├── QuerySimulator.h
│ │ ├── QuerySimulator.cpp
│ │ └── ...
│ ├── system/ # Componentes principais do sistema (LiveDatabase)
│ │ ├── LiveDatabase.h
│ │ ├── LiveDatabase.cpp
│ │ └── ...
│ ├── main.cpp # Ponto de entrada principal da aplicação
│ └── CMakeLists.txt # Arquivo CMake para o diretório 'src'
│
├── include/ # Headers públicos (se você tiver algum que queira acessível globalmente)
│ └── ...
│
├── web/ # Frontend (HTML, CSS, JavaScript)
│ ├── index.html
│ ├── style.css (opcional, se você separar o CSS)
│ ├── script.js (opcional, se você separar o JS)
│ └── ... (outros recursos da web: imagens, fontes, etc.)
│
├── test/ # Testes unitários (altamente recomendado!)
│ ├── CMakeLists.txt
│ ├── database_tests.cpp
│ ├── sensor_tests.cpp
│ └── ...
│
├── scripts/ # Scripts utilitários (opcional)
│ ├── build.sh # Script de build (para conveniência)
│ ├── run.sh # Script de execução
│ └── ...
│
├── build/ # Artefatos de build (criados pelo CMake) - *Adicione isso ao .gitignore*
│ └── ...
│
└── docs/ # Documentação do projeto (opcional, mas boa prática)
├── architecture.md # Descrição detalhada da arquitetura
└── ...
Explicação e Considerações Chave:
CMakeLists.txt (Nível Superior): Este é o arquivo CMake principal que orquestra todo o processo de build. Ele definirá o projeto, encontrará dependências (como SQLite3) e incluirá subdiretórios (src, test).
README.md: Crucial para explicar o que é seu projeto, como construí-lo, como executá-lo e quaisquer dependências.
LICENSE: Especifica como outros podem usar seu código. Escolha uma licença apropriada para seu projeto (MIT, Apache 2.0, GPL, etc.).
.gitignore: Impede que artefatos de build, arquivos temporários e arquivos específicos do editor sejam rastreados pelo Git. Crucialmente, adicione build/ ao seu .gitignore.
src/: É aqui que reside o código C++ principal.
Subdiretórios por Componente: Os diretórios database/, sensors/, monitoring/, simulation/ e system/ organizam o código logicamente por sua função. Isso torna o projeto muito mais fácil de navegar e manter. Cada diretório contém os arquivos .h (cabeçalho) e .cpp (implementação) para as classes correspondentes.
main.cpp: O ponto de entrada da sua aplicação.
CMakeLists.txt (dentro de src/): Este arquivo CMake é específico para construir o backend C++. Ele definirá o(s) executável(eis) e vinculará as bibliotecas necessárias.
include/: Se você tiver arquivos de cabeçalho que precisam ser acessíveis de várias partes do seu projeto (e potencialmente por projetos externos), coloque-os aqui. Neste projeto específico, pode não ser estritamente necessário, pois os cabeçalhos estão localizados com suas implementações.
web/: O código do frontend (HTML, CSS, JavaScript) é bem separado. Isso mantém as preocupações do backend e do frontend distintas. Você poderia até ter um processo de build separado para o frontend (por exemplo, usando um empacotador JavaScript como Webpack ou Parcel) se ele se tornar mais complexo.
test/:Essencial para qualquer projeto sério. Este diretório contém testes unitários. Usar um framework de teste como Google Test (gtest) ou Catch2 é altamente recomendado. O CMakeLists.txt dentro de test/ lida com a construção e execução dos testes.
scripts/: Um lugar para scripts úteis para automatizar tarefas comuns (construção, execução, limpeza, etc.).
build/: É aqui que o CMake colocará os binários compilados, arquivos de objeto e outros artefatos de build. Não adicione este diretório ao controle de versão.
docs/: Para documentação mais extensa, como descrições arquiteturais detalhadas, documentação de API ou guias de usuário.
Princípios Chave:
Separação de Responsabilidades: A estrutura de diretórios separa claramente diferentes partes da aplicação (banco de dados, sensores, monitoramento, frontend).
Modularidade: Cada componente é relativamente autocontido, tornando-o mais fácil de entender, modificar e testar.
Sistema de Build (CMake): O CMake fornece uma maneira consistente e independente de plataforma para construir o projeto.
Teste: O diretório test/ incentiva a escrita de testes unitários para garantir a correção do código e evitar regressões.
Limpeza: O arquivo .gitignore mantém o repositório limpo de arquivos desnecessários.
Como Criar Essa Estrutura (usando a linha de comando):
Preencha CMakeLists.txt (Nível Superior): Comece com uma configuração básica do CMake:
cmake_minimum_required(VERSION 3.10) # Ou superior, se necessárioproject(IndustrialMonitoringSystem)# Encontrar SQLite3find_package(SQLite3 REQUIRED)# Adicionar subdiretóriosadd_subdirectory(src)# add_subdirectory(test) # Descomente quando tiver testes# Você pode adicionar opções para construir o frontend aqui,# ou ter um processo de build separado para ele.
Preencha src/CMakeLists.txt:
add_executable(IndustrialMonitoringSystem main.cpp database/DatabaseManager.cpp sensors/RealTimeDataGenerator.cpp monitoring/DataMonitor.cpp simulation/QuerySimulator.cpp system/LiveDatabase.cpp)target_include_directories(IndustrialMonitoringSystem PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})target_link_libraries(IndustrialMonitoringSystem SQLite::SQLite3 pthread) # Link SQLite3 and pthreads# Se você estiver usando C++17 ou posterior:set_property(TARGET IndustrialMonitoringSystem PROPERTY CXX_STANDARD 17)set_property(TARGET IndustrialMonitoringSystem PROPERTY CXX_STANDARD_REQUIRED ON)
Preencha .gitignore:
build/
*.o
*.exe
*.db # Você pode querer manter arquivos .db de exemplo, mas não os gerados
# Adicione outros arquivos e pastas específicos do editor/IDE aqui
Preencha test/CMakeLists.txt:
# Encontre a biblioteca GoogleTest find_package(GTest REQUIRED) # Habilite os testes enable_testing() # Crie um executável de teste add_executable(DatabaseTests database_tests.cpp) # Vincule o executável de teste ao GoogleTest target_link_libraries(DatabaseTests GTest::GTestMain) # Adicione o teste ao conjunto de testes add_test(NAME DatabaseTests COMMAND DatabaseTests) # Crie um executável de teste add_executable(SensorTests sensor_tests.cpp) # Vincule o executável de teste ao GoogleTest target_link_libraries(SensorTests GTest::GTestMain) # Adicione o teste ao conjunto de testes add_test(NAME SensorTests COMMAND SensorTests)
Esta configuração detalhada fornece uma base sólida para o seu projeto. Lembre-se de instalar as bibliotecas de desenvolvimento SQLite3 (libsqlite3-dev no Debian/Ubuntu ou similar em outros sistemas). Você também precisará de um compilador C++ (GCC, Clang, MSVC) e CMake. Este é um muito bom ponto de partida para um projeto C++ de qualidade profissional.
Visão Geral
Este sistema demonstra uma solução robusta para integração de diversos subsistemas industriais em tempo real usando C++ moderno. A arquitetura implementa um sistema distribuído que coleta dados de sensores, processa-os e permite controle remoto de atuadores em uma planta industrial.
Arquitetura do Sistema
+------------------------+ +------------------------+ +-------------------+
| Sensores Distribuídos | | Sistema de Controle | | Interface HMI |
| (Temperatura/Pressão/ +---->+ Central +---->+ (Web/Mobile/ |
| Vibração/Nível) | | (Processamento/Análise)| | Desktop) |
+------------------------+ +------------------------+ +-------------------+
^ |
| |
v v
+------------------------+ +------------------------+ +-------------------+
| Sistema de | | Banco de Dados | | Sistema de |
| Alarmes e Notificações |<----+ em Tempo Real |<----+ Geração de |
| | | (Série temporal) | | Relatórios |
+------------------------+ +------------------------+ +-------------------+
Implementação do Sistema
1. Código do Sistema de Aquisição de Dados
##include <iostream>#include <sqlite3.h>#include <thread>#include <mutex>#include <chrono>#include <random>#include <vector>#include <atomic>#include <string>#include <sstream>#include <iomanip>#include <ctime>// Classe para gerenciar conexão com banco de dados SQLiteclass DatabaseManager {private: sqlite3* db; std::mutex dbMutex; std::string dbName;public: DatabaseManager(const std::string& dbName) : dbName(dbName), db(nullptr) {} bool open() { std::lock_guard<std::mutex> lock(dbMutex); int rc = sqlite3_open(dbName.c_str(), &db); if (rc != SQLITE_OK) { std::cerr << "Erro ao abrir banco de dados: " << sqlite3_errmsg(db) << std::endl; return false; } return true; } bool executeQuery(const std::string& query) { std::lock_guard<std::mutex> lock(dbMutex); char* errMsg = nullptr; int rc = sqlite3_exec(db, query.c_str(), nullptr, nullptr, &errMsg); if (rc != SQLITE_OK) { std::cerr << "Erro SQL: " << errMsg << std::endl; sqlite3_free(errMsg); return false; } return true; } // Callback para processar resultados de consulta static int queryCallback(void* data, int argc, char** argv, char** azColName) { auto* results = static_cast<std::vector<std::vector<std::string>>*>(data); // Para a primeira linha, adiciona os cabeçalhos if (results->empty()) { std::vector<std::string> headers; for (int i = 0; i < argc; i++) { headers.push_back(azColName[i]); } results->push_back(headers); } // Adiciona os dados da linha std::vector<std::string> row; for (int i = 0; i < argc; i++) { row.push_back(argv[i] ? argv[i] : "NULL"); } results->push_back(row); return 0; } std::vector<std::vector<std::string>> executeSelect(const std::string& query) { std::lock_guard<std::mutex> lock(dbMutex); std::vector<std::vector<std::string>> results; char* errMsg = nullptr; int rc = sqlite3_exec( db, query.c_str(), queryCallback, &results, &errMsg ); if (rc != SQLITE_OK) { std::cerr << "Erro na consulta: " << errMsg << std::endl; sqlite3_free(errMsg); } return results; } void close() { std::lock_guard<std::mutex> lock(dbMutex); if (db) { sqlite3_close(db); db = nullptr; } } ~DatabaseManager() { close(); }};// Classe para gerar dados em tempo realclass RealTimeDataGenerator {private: DatabaseManager& dbManager; std::atomic<bool> running; std::thread generatorThread; std::random_device rd; std::mt19937 gen; // Distribuições para diferentes tipos de dados std::uniform_int_distribution<> sensorIdDist; std::normal_distribution<> temperatureDist; std::normal_distribution<> humidityDist; std::normal_distribution<> pressureDist; std::uniform_real_distribution<> batteryDist; std::string getTimestamp() { auto now = std::chrono::system_clock::now(); auto time_t = std::chrono::system_clock::to_time_t(now); std::stringstream ss; ss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S"); return ss.str(); } // Função que executa em uma thread separada void generatorFunction(int intervalMs) { while (running) { // Gerar dados aleatórios para cada sensor for (int i = 0; i < 5; i++) { int sensorId = sensorIdDist(gen); double temperature = temperatureDist(gen); double humidity = humidityDist(gen); double pressure = pressureDist(gen); double battery = batteryDist(gen); std::string timestamp = getTimestamp(); // Inserir no banco de dados std::stringstream ss; ss << "INSERT INTO sensor_data (sensor_id, temperature, humidity, pressure, battery_level, timestamp) " << "VALUES (" << sensorId << ", " << std::fixed << std::setprecision(2) << temperature << ", " << std::fixed << std::setprecision(2) << humidity << ", " << std::fixed << std::setprecision(2) << pressure << ", " << std::fixed << std::setprecision(2) << battery << ", " << "'" << timestamp << "')"; dbManager.executeQuery(ss.str()); // Criar um evento aleatório (10% de chance) if (std::uniform_real_distribution<>(0, 1)(gen) < 0.1) { std::string eventType; std::string eventDescription; int severity; // Decidir o tipo de evento double eventRand = std::uniform_real_distribution<>(0, 1)(gen); if (eventRand < 0.4) { eventType = "TEMPERATURE_ALERT"; eventDescription = "Temperatura fora dos limites normais"; severity = 2; } else if (eventRand < 0.7) { eventType = "BATTERY_LOW"; eventDescription = "Nível de bateria baixo"; severity = 1; } else if (eventRand < 0.9) { eventType = "PRESSURE_WARNING"; eventDescription = "Pressão anormal detectada"; severity = 3; } else { eventType = "SYSTEM_ERROR"; eventDescription = "Erro de comunicação com sensor"; severity = 4; } std::stringstream eventSs; eventSs << "INSERT INTO events (sensor_id, event_type, description, severity, timestamp) " << "VALUES (" << sensorId << ", " << "'" << eventType << "', " << "'" << eventDescription << "', " << severity << ", " << "'" << timestamp << "')"; dbManager.executeQuery(eventSs.str()); } } // Limpar dados antigos (manter apenas os últimos 1000 registros) dbManager.executeQuery("DELETE FROM sensor_data WHERE id NOT IN (SELECT id FROM sensor_data ORDER BY timestamp DESC LIMIT 1000)"); dbManager.executeQuery("DELETE FROM events WHERE id NOT IN (SELECT id FROM events ORDER BY timestamp DESC LIMIT 500)"); // Aguardar o intervalo configurado std::this_thread::sleep_for(std::chrono::milliseconds(intervalMs)); } }public: RealTimeDataGenerator(DatabaseManager& db) : dbManager(db), running(false), gen(rd()), sensorIdDist(1, 10), temperatureDist(22.0, 5.0), // Média 22°C, desvio padrão 5°C humidityDist(60.0, 15.0), // Média 60%, desvio padrão 15% pressureDist(1013.0, 10.0), // Média 1013 hPa, desvio padrão 10 hPa batteryDist(0.5, 1.0) // Entre 50% e 100% {} bool initialize() { // Criar tabelas se não existirem if (!dbManager.executeQuery( "CREATE TABLE IF NOT EXISTS sensor_data (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "sensor_id INTEGER NOT NULL," "temperature REAL," "humidity REAL," "pressure REAL," "battery_level REAL," "timestamp TEXT NOT NULL" ")" )) { return false; } if (!dbManager.executeQuery( "CREATE TABLE IF NOT EXISTS events (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "sensor_id INTEGER NOT NULL," "event_type TEXT NOT NULL," "description TEXT," "severity INTEGER," "timestamp TEXT NOT NULL" ")" )) { return false; } // Criar índices para melhorar performance dbManager.executeQuery("CREATE INDEX IF NOT EXISTS idx_sensor_data_timestamp ON sensor_data(timestamp)"); dbManager.executeQuery("CREATE INDEX IF NOT EXISTS idx_sensor_data_sensor_id ON sensor_data(sensor_id)"); dbManager.executeQuery("CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp)"); dbManager.executeQuery("CREATE INDEX IF NOT EXISTS idx_events_sensor_id ON events(sensor_id)"); return true; } void start(int intervalMs = 1000) { if (!running) { running = true; generatorThread = std::thread(&RealTimeDataGenerator::generatorFunction, this, intervalMs); std::cout << "Gerador de dados iniciado com intervalo de " << intervalMs << "ms" << std::endl; } } void stop() { if (running) { running = false; if (generatorThread.joinable()) { generatorThread.join(); } std::cout << "Gerador de dados parado" << std::endl; } } ~RealTimeDataGenerator() { stop(); }};// Classe para exibir dados em tempo real no consoleclass DataMonitor {private: DatabaseManager& dbManager; std::atomic<bool> running; std::thread monitorThread; void monitorFunction(int intervalMs) { while (running) { // Exibir últimas leituras std::cout << "\n=========== ÚLTIMAS LEITURAS DE SENSORES ===========" << std::endl; auto results = dbManager.executeSelect( "SELECT sensor_id, temperature, humidity, pressure, battery_level, timestamp " "FROM sensor_data ORDER BY timestamp DESC LIMIT 5" ); displayResults(results); // Exibir eventos recentes std::cout << "\n=========== EVENTOS RECENTES ===========" << std::endl; auto events = dbManager.executeSelect( "SELECT sensor_id, event_type, description, severity, timestamp " "FROM events ORDER BY timestamp DESC LIMIT 3" ); displayResults(events); // Estatísticas std::cout << "\n=========== ESTATÍSTICAS ===========" << std::endl; auto stats = dbManager.executeSelect( "SELECT sensor_id, " "AVG(temperature) as avg_temp, " "MIN(temperature) as min_temp, " "MAX(temperature) as max_temp, " "AVG(battery_level) as avg_battery " "FROM sensor_data " "GROUP BY sensor_id " "ORDER BY sensor_id " "LIMIT 10" ); displayResults(stats); std::cout << "\n" << std::string(50, '-') << std::endl; // Aguardar o intervalo configurado std::this_thread::sleep_for(std::chrono::milliseconds(intervalMs)); } } void displayResults(const std::vector<std::vector<std::string>>& results) { if (results.size() <= 1) { std::cout << "Sem dados disponíveis." << std::endl; return; } // Determinar largura de cada coluna std::vector<size_t> colWidths(results[0].size(), 0); for (const auto& row : results) { for (size_t i = 0; i < row.size(); i++) { colWidths[i] = std::max(colWidths[i], row[i].length() + 2); } } // Exibir cabeçalhos for (size_t i = 0; i < results[0].size(); i++) { std::cout << std::left << std::setw(colWidths[i]) << results[0][i] << " | "; } std::cout << std::endl; // Linha separadora for (size_t i = 0; i < results[0].size(); i++) { std::cout << std::string(colWidths[i], '-') << "-+-"; } std::cout << std::endl; // Exibir dados for (size_t row = 1; row < results.size(); row++) { for (size_t i = 0; i < results[row].size(); i++) { std::cout << std::left << std::setw(colWidths[i]) << results[row][i] << " | "; } std::cout << std::endl; } }public: DataMonitor(DatabaseManager& db) : dbManager(db), running(false) {} void start(int intervalMs = 5000) { if (!running) { running = true; monitorThread = std::thread(&DataMonitor::monitorFunction, this, intervalMs); std::cout << "Monitor de dados iniciado com intervalo de " << intervalMs << "ms" << std::endl; } } void stop() { if (running) { running = false; if (monitorThread.joinable()) { monitorThread.join(); } std::cout << "Monitor de dados parado" << std::endl; } } ~DataMonitor() { stop(); }};// Classe para simular consultas de usuáriosclass QuerySimulator {private: DatabaseManager& dbManager; std::atomic<bool> running; std::thread simulatorThread; std::mt19937 gen; std::random_device rd; // Vetor de possíveis consultas std::vector<std::string> queries = { "SELECT * FROM sensor_data WHERE temperature > 25 ORDER BY timestamp DESC LIMIT 5", "SELECT * FROM sensor_data WHERE battery_level < 0.7 ORDER BY timestamp DESC LIMIT 5", "SELECT COUNT(*) as total_events, event_type FROM events GROUP BY event_type", "SELECT sensor_id, AVG(temperature) as avg_temp FROM sensor_data GROUP BY sensor_id", "SELECT * FROM events WHERE severity > 2 ORDER BY timestamp DESC LIMIT 3", "SELECT strftime('%H', timestamp) as hour, COUNT(*) as count FROM sensor_data GROUP BY hour", "SELECT * FROM sensor_data WHERE sensor_id = 3 ORDER BY timestamp DESC LIMIT 5", "SELECT * FROM events WHERE event_type = 'TEMPERATURE_ALERT' ORDER BY timestamp DESC LIMIT 3" }; void simulatorFunction(int minIntervalMs, int maxIntervalMs) { std::uniform_int_distribution<> queryDist(0, queries.size() - 1); std::uniform_int_distribution<> intervalDist(minIntervalMs, maxIntervalMs); while (running) { // Selecionar uma consulta aleatória std::string query = queries[queryDist(gen)]; // Executar a consulta std::cout << "\n=========== CONSULTA AD HOC ===========" << std::endl; std::cout << "Executando: " << query << std::endl; auto results = dbManager.executeSelect(query); // Exibir resultados if (results.size() <= 1) { std::cout << "Sem resultados." << std::endl; } else { std::cout << "Encontrados " << results.size() - 1 << " resultados." << std::endl; } // Aguardar um intervalo aleatório int interval = intervalDist(gen); std::this_thread::sleep_for(std::chrono::milliseconds(interval)); } }public: QuerySimulator(DatabaseManager& db) : dbManager(db), running(false), gen(rd()) {} void start(int minIntervalMs = 8000, int maxIntervalMs = 15000) { if (!running) { running = true; simulatorThread = std::thread(&QuerySimulator::simulatorFunction, this, minIntervalMs, maxIntervalMs); std::cout << "Simulador de consultas iniciado com intervalo entre " << minIntervalMs << "ms e " << maxIntervalMs << "ms" << std::endl; } } void stop() { if (running) { running = false; if (simulatorThread.joinable()) { simulatorThread.join(); } std::cout << "Simulador de consultas parado" << std::endl; } } ~QuerySimulator() { stop(); }};// Classe principal do sistemaclass LiveDatabase {private: DatabaseManager dbManager; RealTimeDataGenerator dataGenerator; DataMonitor dataMonitor; QuerySimulator querySimulator;public: LiveDatabase(const std::string& dbName) : dbManager(dbName), dataGenerator(dbManager), dataMonitor(dbManager), querySimulator(dbManager) {} bool initialize() { if (!dbManager.open()) { std::cerr << "Falha ao abrir banco de dados." << std::endl; return false; } if (!dataGenerator.initialize()) { std::cerr << "Falha ao inicializar gerador de dados." << std::endl; return false; } return true; } void start() { std::cout << "Iniciando sistema de banco de dados vivo..." << std::endl; dataGenerator.start(2000); // Gerar dados a cada 2 segundos std::this_thread::sleep_for(std::chrono::seconds(2)); // Esperar dados iniciais dataMonitor.start(7000); // Atualizar monitor a cada 7 segundos querySimulator.start(8000, 15000); // Simular consultas a cada 8-15 segundos } void stop() { std::cout << "Parando sistema..." << std::endl; querySimulator.stop(); dataMonitor.stop(); dataGenerator.stop(); }};int main() { LiveDatabase liveDb("sensors_live.db"); if (!liveDb.initialize()) { std::cerr << "Falha ao inicializar o sistema." << std::endl; return 1; } liveDb.start(); std::cout << "Sistema em execução. Pressione Enter para encerrar..." << std::endl; std::cin.get(); liveDb.stop(); return 0;}
Coleta de dados em tempo real de múltiplos sensores
Thread-safe com controle de concorrência
Polling configurável
Estruturas de dados otimizadas para tempo real
2. Sistema de Processamento
Análise de valores para detecção de anomalias
Sistema de alarmes baseado em limiares configuráveis
Processamento paralelo para melhor desempenho
3. Comunicação em Tempo Real
WebSockets para comunicação bidirecional de baixa latência
Serialização JSON para interoperabilidade
Reconexão automática em caso de falhas
4. Interface em Tempo Real
Dashboard responsivo com atualizações em tempo real
Indicadores visuais para alarmes
Design adaptável a diferentes dispositivos
Benefícios da Arquitetura
Baixa Latência: O sistema é capaz de processar e reagir a eventos em milissegundos.
Alta Disponibilidade: Mecanismos de recuperação automática garantem funcionamento contínuo.
Escalabilidade: Arquitetura modular permite adicionar novos sensores e subsistemas.
Interoperabilidade: Padrões abertos (JSON, WebSockets) facilitam integração com outros sistemas.
Robustez: Tratamento de erros em múltiplas camadas evita falhas em cascata.
Aplicações Industriais
Este sistema pode ser adaptado para monitoramento e controle em diversos setores:
Indústria Química: Monitoramento de pressão, temperatura e nível em reatores
Manufatura: Controle de processos de produção e detecção de falhas em equipamentos
Energia: Monitoramento de usinas e transmissão de energia
Petróleo e Gás: Supervisão de oleodutos e plataformas
Mineração: Monitoramento de operações de extração e processamento
Conclusão
Esta implementação demonstra como C++ moderno pode ser usado para criar sistemas de integração em tempo real robustos e de alto desempenho. O sistema combina múltiplas tecnologias (threads, mutexes, websockets, interface web) para fornecer uma solução completa para monitoramento industrial.