O que você vai construir
Um programa de linha de comando que recebe leituras simuladas de temperatura de dois sensores e mostra a média de um deles. Esse é um primeiro exercício da camada de software de um sistema IoT: organizar amostras, selecionar um dispositivo e lidar com a ausência de dados.
Depois da média de duas temperaturas, você vai guardar várias leituras e escolher de qual sensor calcular a média. Há três novidades de C++ para explorar: uma coleção, uma função e um resultado que pode não existir.
Continue no projeto ola-kinein, na Vectis, com as ferramentas do primeiro tutorial. Também é possível acompanhar pelo terminal com g++ e suporte a C++20. As amostras continuam inventadas: esta etapa ainda roda inteiramente no computador.
Passo 1: escreva o programa
Abra o mesmo src/main.cpp e substitua o cálculo anterior pelo código abaixo. Salve antes de compilar. Você continua no mesmo projeto e não precisa alterar o CMakeLists.txt.
Se estiver usando apenas o terminal, substitua o conteúdo do seu main.cpp.
#include <array>
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <optional>
#include <span>
#include <string>
#include <string_view>
struct Leitura {
std::string sensor;
int milicelsius;
};
std::optional<double> media_celsius(
std::span<const Leitura> leituras,
std::string_view sensor) {
double soma = 0.0;
std::size_t quantidade = 0;
for (const Leitura& leitura : leituras) {
if (leitura.sensor == sensor) {
soma += static_cast<double>(leitura.milicelsius) / 1000.0;
++quantidade;
}
}
if (quantidade == 0) {
return std::nullopt;
}
return soma / static_cast<double>(quantidade);
}
int main() {
const std::array<Leitura, 4> leituras{{
{"sala", 21500},
{"externo", 19100},
{"sala", 22000},
{"sala", 21750},
}};
std::cout << std::fixed << std::setprecision(2);
for (std::string_view sensor : {"sala", "patio"}) {
const auto media = media_celsius(leituras, sensor);
if (media) {
std::cout << sensor << ": " << *media << " C\n";
} else {
std::cout << sensor << ": sem leituras\n";
}
}
}
Cada temperatura é armazenada como um inteiro em milésimos de grau Celsius: 21500 representa 21,5 °C. A conversão para double acontece quando calculamos a média.
Passo 2: compile e confira o resultado
Na Vectis 0.3.5: salve com Ctrl+S, compile com Ctrl+Alt+B e espere o sucesso no painel Build. Mantenha um terminal aberto (Alt+F12) e execute pelo ▶, como na etapa anterior.
Pelo terminal: no diretório onde salvou main.cpp, execute:
g++ -std=c++20 -Wall -Wextra -Wpedantic -Werror main.cpp -o telemetria
./telemetria
Resultado esperado:
sala: 21.75 C
patio: sem leituras
As três leituras da sala somam 65,25 °C; divididas por três, produzem 21,75 °C. O pátio não aparece nas amostras, então o programa informa que não há leituras em vez de dividir por zero.
Se o compilador disser que não conhece std::span, confirme se aceita -std=c++20. No GCC, essa opção seleciona o padrão C++20.
Passo 3: entenda as escolhas de C++ moderno
std::arraymantém um conjunto pequeno e fixo de amostras neste exercício. Em uma aplicação que acumula amostras dinamicamente,std::vectoré uma escolha mais adequada.std::stringguarda o nome de cada sensor junto com a leitura. Jástd::string_viewrecebe o nome usado na busca sem precisar criar outra string.std::span<const Leitura>permite percorrer as amostras sem copiá-las. É uma visão: o programa que chama a função continua responsável por manter as amostras vivas durante a chamada.std::optional<double>representa uma média que pode não existir. O código só acessa*mediadepois de verificar se há valor.
Os conceitos de interfaces explícitas, objetos que possuem seus dados e visões sem posse são desenvolvidos nas C++ Core Guidelines. O uso de std::span passou a fazer parte da biblioteca em C++20, conforme os documentos do comitê WG21. Este texto e o exemplo foram escritos para este guia; não reproduzem a documentação dessas fontes.
Passo 4: faça três pequenas mudanças
- Troque
"patio"por"externo"no laço final. A segunda linha deve passar a mostrarexterno: 19.10 C. - Adicione
{"sala", 22500}ao fim das amostras e altere o tamanho destd::array<Leitura, 4>parastd::array<Leitura, 5>. A média da sala deve passar a21.94 Capós o arredondamento para duas casas. - Remova ou renomeie todas as leituras de
"sala". O programa deve mostrarsala: sem leituras.
Recompile e execute após cada mudança. Se o resultado for diferente, confira o nome do sensor, a quantidade de elementos do std::array e a unidade de cada valor.
Próximos estudos
Você chegou ao fim deste percurso: seu ola-kinein foi de uma mensagem a um cálculo com várias leituras. Antes de acrescentar um dispositivo ou rede, pratique os exercícios e confira a saída. Este exemplo ainda não trata leituras inválidas nem o instante em que cada amostra foi obtida.
Para avançar por conta própria, uma boa tarefa é escrever testes para media_celsius com CTest e estudar como validar uma entrada recebida pelo programa.
Para aprofundar, consulte também a documentação do GCC sobre padrões de linguagem e o tutorial oficial de testes com CMake e CTest.