Fechamento do ano — Arduino e IoT — semana 15 do 3o trimestre

Informatica · Conteudo · publicado em 02/10/2026
Semana 15 · Fechamento do ano — Material de Apoio Arduino

Semana 15 de 15· 3o trimestre · 05/09 a 10/12

Fechamento do ano

Encerramento, duvidas e a ponte para o que vem depois.

Aula 1 — Apresentacao dos projetos e feedback

Objetivos

final em quatro minutos, com a placa na bancada rodando o firmware entregue.

  • Dar elogio específico a um projeto de colega, citando a decisão técnica e não a impressão.
  • Fazer crítica construtiva com caminho: dizer o problema e dizer onde mexer.
  • Responder uma pergunta da turma em voz alta, e registrar a que ninguém soube responder.
  • Ler em voz alta o que eu faria diferente, com o motivo em cada frase.

Material

  • 1 ESP32 DevKit V1 por aluno, com o firmware do projeto final gravado e o cabo USB
  • Projetor, com o monitor serial da placa de apresentação e o terminal do projeto lado a lado
  • Folha por aluno com o roteiro de 4 minutos, o bloco de elogio e o bloco de pergunta
  • Folha do professor com a lista de elogio, crítica e pergunta escrita antes de começar
  • Cronômetro de parede, porque quatro minutos por aluno é o que segura o dia em 50

Conceitos

A apresentação é uma prova de entrega, e a placa é a prova

O projeto final do ano é a entrega de um sistema com as sete camadas que o sketch lista: hardware, firmware, rede, servidor, banco, entrega e o próprio projeto. O que muda na última semana não é o escopo — é o que a turma precisa demonstrar.

A placa está na bancada por um motivo técnico, e não por enfeite: o monitor serial com a VERSAO_FIRMWARE gravada é a prova viva de que o firmware do aluno ainda roda depois de entregue. Um repositório no ar prova que alguém escreveu o arquivo; a placa subindo prova que o arquivo compila, gravou e está executando diante da turma. Se a placa não subir, o aluno descobre isso na apresentação — que é exatamente onde a informação é útil.

Os quatro minutos por aluno não são generousidade. Com seis alunos e cinquenta minutos, sobram vinte e seis minutos para discussão, e a discussão é a parte que transforma apresentação em feedback. O professor cronometra em voz alta, e o aluno que passou do tempo sabe onde cortar no ensaio de hoje à noite.

Elogio específico e crítica com caminho

O que distingue esta aula das outras trinta é que o feedback aqui é o conteúdo, e não um extra. A regra do sketch tem três partes, e a ordem delas é o que evita que a crítica soe como ataque:

ParteO que éO que não é
elogio específico"a consulta do histórico tem índice e página""bom trabalho"
crítica construtivao problema e o caminhosó o problema
uma pergunta que fica"e se a consulta estourar o tempo?"um veredito sobre o projeto

"Bom trabalho" não é elogio, e a razão é mecânica: não diz o que foi bom e não muda o comportamento de ninguém. Um elogio que não muda comportamento é elogio nenhum com palavras a mais. O elogio útil aponta uma decisão e explica por que ela é boa — a chave de idempência que evitou o alerta duplo, o README com o passo de instalação que funciona, o health check que não consulta o banco.

A crítica construtiva é a parte mais difícil para quem apresenta e a mais fácil para quem avalia. Crítica sem caminho é só decoração: "faltou teste" sem dizer qual teste e sem dizer onde. O caminho é o que faz a crítica ser útil — e é por isso que o professor escreve na lousa a frase inteira, não a metade ruim.

A pergunta da turma é o que o aluno leva para casa

O feedback que permanece é a pergunta da turma, não o elogio. A pergunta é a única parte da apresentação que o aluno ainda não sabe responder, e é a única que muda o comportamento dele.

O sketch separa as perguntas respondidas das que não foram. Uma das três perguntas fica com respondida: falso, e isso é proposital: a pergunta sem resposta não é falta do aluno, é a que ele vai descobrir em casa com o código na mão. O professor anota na lousa e cobra na próxima aula, se a turma voltar. Responder pergunta é a habilidade que fecha o ano, e ela é a oitava do inventário de ontem, a que ficou sem consolidada: ela só se prova aqui, em voz alta, para alguém que não conhece o código.

A cena que o professor provoca quando ninguém sabe responder é a que vale: alguém da turma precisa ensinar o outro, e é isso que a apresentação cobra de todo mundo. Ensinar exige ordenar a ideia para caber em duas frases, e a ordem das frases revela o que a pessoa realmente entendeu. Quem consegue explicar em voz alta consolidou; quem lê o código e gagueja, ainda não.

E é essa a resposta à pergunta que a lousa faz no começo da aula: demonstrar o projeto, ou mostrar o projeto. A diferença é de foco: demonstrar é rodar o sistema diante da turma e deixar que ela tire a conclusão; mostrar é apontar a decisão e dizer por que ela ficou daquela maneira. O aluno que apenas demonstra com a placa ligada passa a impressão de que o projeto funciona; o aluno que mostra diz qual parte é difícil e por que ela ficou do jeito que ficou — e é essa frase que faz a turma aprender com um projeto que não é o dele.

E é por isso que a apresentação é do projeto da turma inteiro, e não só do aluno que está falando. Cada aluno mostra o projeto dele, mas o que a turma precisa ver de todos é a leitura de conjunto: seis sistemas que compartilham as mesmas camadas, apontando para a lista que a placa imprimiu no fim da sessão. O professor anota na lousa, ao lado do nome de cada aluno, três palavras: o que a decisão foi, por que foi boa, e a pergunta que ficou. São três palavras porque é o que cabe numa folha e é o que o aluno vai consultar em dezembro quando lembrar do ano.

O que eu faria diferente: a pergunta mais difícil do curso

"O que eu faria diferente" é a pergunta mais difícil do curso, e é a última porque ela é a única que o aluno não pode responder lendo o material. Ela tem três partes e o professor cobra as três:

  1. o que eu trocaria no meu projeto — com nome, não com adjetivo
  2. o que eu aprendi com o projeto de vocês — algo que o projeto dos outros ensinou
  3. o que eu levaria para o próximo ano — uma mudança concreta no curso, com o motivo

O que torna a pergunta útil não é a resposta, é o formato. "Faria diferente" sem o motivo é o mesmo "faria diferente" com mais palavras: só muda a superfície. Com o motivo, a frase vira decisão de projeto, e decisão de projeto é o que o professor consegue ler no painel de amanhã e reconhecer.

E há um efeito colateral que o professor explica em voz alta: responder essa pergunta em público ensina a turma que o professor também já entregou projeto com defeito. Ninguém aprende a pedir crítica num curso em que o professor nunca admite uma.

Atividade

Montagem: botao com pull-up no pino 0 para avançar de aluno, jumper de saída no pino 2 para o LED de status, ground no GND. A placa fica com o firmware do projeto final do aluno gravado antes da aula começar; o sketch da resolução é o roteiro da sessão, e o botao avança o LED a cada apresentação.

  1. Grave o sketch da resolução e rode no serial. Anote a versão do firmware que a placa imprimiu e compare com a versão do seu projeto final. As duas batem?
  2. Escreva o roteiro da sua apresentação em quatro minutos: o que você mostra, em que ordem, e o que você mostra se sobrar tempo. Ensaiar com cronômetro, não a olho.
  3. Apresente. Enquanto fala, aponte a placa na tela pelo menos uma vez, e diga a versão do firmware rodando. Diga de onde nasce o dado (sensor ou painel) e onde ele termina (banco ou tela).
  4. Ao terminar, escreva o elogio específico do projeto de um colega: cite a decisão técnica dele e explique por que ela é boa. Releia e confira que não tem "bom trabalho" em nenhum ponto.
  5. Ao terminar, escreva a crítica construtiva desse mesmo projeto: o problema e o caminho, em duas frases. Se você só escreveu o problema, reescreva com o caminho.
  6. Escreva a pergunta que você levaria para esse projeto e a resposta que você daria. Releia a resposta em voz alta, como se o colega estivesse perguntando. Se você gaguejar, a resposta ainda não está pronta.
  7. Leia em voz alta a resposta de "o que eu faria diferente", nas três partes: o que trocaria, o que aprendeu com os projetos dos outros, o que levaria para o próximo ano.
  8. Marque no seu inventário de ontem a oitava habilidade — explicar para o outro — e diga em uma frase em qual das suas respostas você conseguiu sem olhar o material.

Nota: 12 pontos. Critério de fim: elogio específico com a decisão técnica nomeada, crítica com caminho escrito, e a oitava habilidade do inventário marcada com o exemplo que a prova.

Resolucao

// Aula 1 do dia 15: apresentacao dos projetos e feedback.
//
// A placa e a mesa de som da apresentacao. Enquanto cada aluno mostra o
// projeto, a placa roda o roteiro da sessao e imprime o que o professor
// anotou na lousa: o que foi demonstrado, o elogio especifico e a pergunta
// que a turma fez.
//
// Por que a placa faz parte de uma apresentacao: e o unico jeito de o
// aluno mostrar que o firmware DELE continua rodando depois de entregar. O
// monitor serial com a versao 2.0.0 e a prova viva de que a entrega nao foi
// so um arquivo.
//
// A regra de feedback que o professor escreve na lousa e a aula inteira:
// elogio especifico, critica construtiva, e uma pergunta que o aluno leva
// para casa. "Bom trabalho" nao e elogio: nao diz o que foi bom e nao muda
// o comportamento de ninguem.

#include <Arduino.h>

// Versao do firmware do aluno. O professor compara com a da lousa.
#define VERSAO_FIRMWARE "2.0.0"

#define ID_DISPOSITIVO "esp32-bancada-01"

// Quantos alunos apresentam. A turma do trimestre tem este tamanho, e o
// numero define o tempo: 4 minutos por aluno, com sobra para a duvida.
const int TOTAL_DE_ALUNOS = 6;

// Minutos por apresentacao. Com 6 alunos e 50 minutos, 4 minutos por aluno
// deixa 26 minutos de discussao, que e onde a aula vale.
const int MINUTOS_POR_APRESENTACAO = 4;

// ------------------------------------------------------------------ pinos

const int PIN_LED_STATUS = 2;
const int PIN_BOTAO_PROXIMO = 0;

// ------------------------------------------------------------------ tipos

struct Aluno {
  const char* nome;
  const char* projeto;
  const char* oQueMostrou;
  const char* elogio;
  const char* perguntaDaTurma;
  const char* respostaDoAluno;
  bool respondeuTudo;
};

struct BlocoDoDia {
  const char* quando;
  const char* oQue;
  int minutos;
};

struct Pergunta {
  const char* deQuem;
  const char* oQue;
  const char* respostaEsperada;
  bool respondida;
};

// ------------------------------------------------------------- montagem

Aluno alunos[TOTAL_DE_ALUNOS];
int totalDeAlunos = 0;

BlocoDoDia blocos[5];
int totalDeBlocos = 0;

Pergunta perguntas[3];
int totalDePerguntas = 0;
int perguntasRespondidas = 0;

void montarAlunos() {
  // Os nomes sao de exemplo: o professor troca pela lista da turma. O que
  // importa e a estrutura do feedback, que e a mesma para todo mundo.
  alunos[0].nome = "aluno 1";
  alunos[0].projeto = "estacao com login e historico";
  alunos[0].oQueMostrou = "cadastro, sessao, painel com grafico";
  alunos[0].elogio = "a consulta do historico tem indice e pagina";
  alunos[0].perguntaDaTurma = "e se a consulta estourar o tempo?";
  alunos[0].respostaDoAluno = "tem o tempo de resposta no log, e pagina de 20";
  alunos[0].respondeuTudo = true;

  alunos[1].nome = "aluno 2";
  alunos[1].projeto = "alerta de temperatura com fila";
  alunos[1].oQueMostrou = "grafico historico e alerta em tempo real";
  alunos[1].elogio = "a chave de idempotencia evitou o alerta duplo";
  alunos[1].perguntaDaTurma = "e se o broker cair?";
  alunos[1].respostaDoAluno = "a placa guarda a leitura e reenvia com a mesma chave";
  alunos[1].respondeuTudo = true;

  alunos[2].nome = "aluno 3";
  alunos[2].projeto = "portao e automacao com dois papeis";
  alunos[2].oQueMostrou = "login, painel, migracao e teste";
  alunos[2].elogio = "o README tem o passo de instalacao que funciona";
  alunos[2].perguntaDaTurma = "quem da o papel de administrador?";
  alunos[2].respostaDoAluno = "so quem ja e admin, checado no servidor";
  alunos[2].respondeuTudo = true;

  alunos[3].nome = "aluno 4";
  alunos[3].projeto = "monitor de energia com deep sleep";
  alunos[3].oQueMostrou = "medicao de consumo e tempo de bateria";
  alunos[3].elogio = "mediu antes de otimizar, e o numero esta no README";
  alunos[3].perguntaDaTurma = "quanto dura a bateria de verdade?";
  alunos[3].respostaDoAluno = "uns 30 dias no modo de sono profundo";
  alunos[3].respondeuTudo = true;

  alunos[4].nome = "aluno 5";
  alunos[4].projeto = "trilha de auditoria com log estruturado";
  alunos[4].oQueMostrou = "busca por identificador e filtro no log";
  alunos[4].elogio = "achou o erro de um dispositivo pelo id, em dois minutos";
  alunos[4].perguntaDaTurma = "e se o id for do cliente e nao do dispositivo?";
  alunos[4].respostaDoAluno = "o id propaga; o do dispositivo vai no cabecalho";
  alunos[4].respondeuTudo = false;

  alunos[5].nome = "aluno 6";
  alunos[5].projeto = "API documentada e deploy com health check";
  alunos[5].oQueMostrou = "OpenAPI, container e health check";
  alunos[5].elogio = "o health check nao consulta o banco, como deve ser";
  alunos[5].perguntaDaTurma = "e se o health check ficar verde e o banco cair?";
  alunos[5].respostaDoAluno = "a rota de dependencia responde separadamente";
  alunos[5].respondeuTudo = true;

  totalDeAlunos = 6;
}

void montarBlocos() {
  blocos[0].quando = "0 a 6 min";
  blocos[0].oQue = "abertura: o que a turma construiu em 30 aulas";
  blocos[0].minutos = 6;

  blocos[1].quando = "6 a 30 min";
  blocos[1].oQue = "as 6 apresentacoes, 4 minutos cada";
  blocos[1].minutos = 24;

  blocos[2].quando = "30 a 38 min";
  blocos[2].oQue = "as 3 perguntas da turma, uma por aluno sorteado";
  blocos[2].minutos = 8;

  blocos[3].quando = "38 a 44 min";
  blocos[3].oQue = "o que eu faria diferente, lido em voz alta";
  blocos[3].minutos = 6;

  blocos[4].quando = "44 a 50 min";
  blocos[4].oQue = "o professor le as anotacoes da placa, uma por uma";
  blocos[4].minutos = 6;

  totalDeBlocos = 5;
}

void montarPerguntas() {
  perguntas[0].deQuem = "aluno 1";
  perguntas[0].oQue = "qual camada do seu projeto demorou mais e por que";
  perguntas[0].respostaEsperada = "o banco, porque a migracao foi feita depois da regra";
  perguntas[0].respondida = true;

  perguntas[1].deQuem = "aluno 4";
  perguntas[1].oQue = "qual numero voce mediu antes de escolher o deep sleep";
  perguntas[1].respostaEsperada = "o consumo em modo acordada, em microamperes";
  perguntas[1].respondida = true;

  perguntas[2].deQuem = "aluno 5";
  perguntas[2].oQue = "o que faltou responder da sua pergunta da turma";
  perguntas[2].respostaEsperada = "a propagacao do id no log, que ele vaia implementar";
  perguntas[2].respondida = false;

  totalDePerguntas = 3;
  perguntasRespondidas = 2;
}

// ------------------------------------------------------------------ saida

void imprimirRoteiro() {
  Serial.println("========================================");
  Serial.println(" o roteiro da sessao");
  Serial.println("========================================");
  int soma = 0;
  for (int i = 0; i < totalDeBlocos; i++) {
    Serial.println("  " + String(blocos[i].quando) + " | " +
                   String(blocos[i].minutos) + " min | " + String(blocos[i].oQue));
    soma += blocos[i].minutos;
  }
  Serial.println();
  Serial.println("soma: " + String(soma) + " min | por aluno: " +
                 String(MINUTOS_POR_APRESENTACAO) + " min");
  Serial.println();
}

void imprimirAlunos() {
  Serial.println("========================================");
  Serial.println(" quem apresenta o que");
  Serial.println("========================================");
  for (int i = 0; i < totalDeAlunos; i++) {
    Serial.println();
    Serial.println("  " + String(alunos[i].nome) + " — " + String(alunos[i].projeto));
    Serial.println("    mostrou: " + String(alunos[i].oQueMostrou));
    Serial.println("    elogio:  " + String(alunos[i].elogio));
    Serial.println("    pergunta: " + String(alunos[i].perguntaDaTurma));
    Serial.println("    resposta: " + String(alunos[i].respostaDoAluno));
  }
  Serial.println();
}

void imprimirRegraDoFeedback() {
  Serial.println("========================================");
  Serial.println(" a regra do feedback, em tres partes");
  Serial.println("========================================");
  Serial.println();
  Serial.println("1. ELOGIO ESPECIFICO");
  Serial.println("   'a consulta do historico tem indice e pagina'");
  Serial.println("   'bom trabalho' nao e elogio: nao diz o que foi bom e nao");
  Serial.println("   muda o comportamento de ninguem. elogio generico e o mesmo");
  Serial.println("   que elogio nenhum, so que com palavras a mais.");
  Serial.println();
  Serial.println("2. CRITICA CONSTRUTIVA");
  Serial.println("   'o health check consulta o banco' + 'tire essa consulta e");
  Serial.println("   faca a dependencia aparecer em outra rota'");
  Serial.println("   critica sem caminho e so quedacao. o caminho e o que faz a");
  Serial.println("   critica ser util.");
  Serial.println();
  Serial.println("3. UMA PERGUNTA QUE FICA");
  Serial.println("   'e se a consulta estourar o tempo?'");
  Serial.println("   pergunta e o que o aluno leva para casa. elogio e o que o");
  Serial.println("   aluno ja sabe; pergunta e o que ele ainda nao sabe.");
  Serial.println();
  Serial.println("a ordem importa: elogio especifico primeiro, para o elogio");
  Serial.println("nao soar como consolo; depois a critica, que precisa de um");
  Serial.println("elogio antes para nao soar como ataque; depois a pergunta.");
  Serial.println();
}

void imprimirPerguntas() {
  Serial.println("========================================");
  Serial.println(" as perguntas da turma");
  Serial.println("========================================");
  for (int i = 0; i < totalDePerguntas; i++) {
    Serial.println();
    Serial.println("  " + String(perguntas[i].deQuem) + " pergunta: " +
                   String(perguntas[i].oQue));
    Serial.println("    resposta esperada: " + String(perguntas[i].respostaEsperada));
    Serial.println("    respondida: " + String(perguntas[i].respondida ? "sim" : "NAO"));
  }
  Serial.println();
  Serial.println("respondidas: " + String(perguntasRespondidas) + " de " +
                 String(totalDePerguntas));
  Serial.println();
  Serial.println("a pergunta nao respondida nao e falta do aluno: e a que");
  Serial.println("ele vai descobrir em casa, com o codigo na mao. o professor");
  Serial.println("anota na lousa e cobra na proxima aula, se a turma voltar.");
  Serial.println();
}

void imprimirOQueFariaDiferente() {
  Serial.println("========================================");
  Serial.println(" o que eu faria diferente");
  Serial.println("========================================");
  Serial.println("o professor pede esta parte em voz alta, para a turma inteira.");
  Serial.println("serve para duas coisas: mostra que o professor tambem teve");
  Serial.println("projeto com defeito, e mostra o formato de uma resposta util.");
  Serial.println();
  Serial.println("  1. o que eu trocaria no MEU projeto");
  Serial.println("     'eu comecaria pelo teste da regra, e nao pela migration'");
  Serial.println();
  Serial.println("  2. o que eu aprendi com o projeto de voces");
  Serial.println("     'a duvida real de vcs foi de escopo, e nao de sintaxe'");
  Serial.println();
  Serial.println("  3. o que eu levaria para o proximo ano");
  Serial.println("     'mais tempo em migration, que e onde a turma mais travou'");
  Serial.println();
  Serial.println("resposta em tres frases, com nome proprio e com o motivo.");
  Serial.println("'faria diferente' sem o motivo e so o 'faria diferente'");
  Serial.println("com mais palavras.");
  Serial.println();
}

// ---------------------------------------------------------------- setup

void setup() {
  Serial.begin(115200);
  delay(300);

  pinMode(PIN_LED_STATUS, OUTPUT);
  pinMode(PIN_BOTAO_PROXIMO, INPUT_PULLUP);
  digitalWrite(PIN_LED_STATUS, HIGH);

  Serial.println();
  Serial.println("========================================");
  Serial.println(" apresentacao dos projetos — v" + String(VERSAO_FIRMWARE));
  Serial.println("========================================");
  Serial.println("dispositivo do aluno: " + String(ID_DISPOSITIVO));
  Serial.println("cpu: " + String(getCpuFrequencyMhz()) + " MHz | heap: " +
                 String(ESP.getFreeHeap()) + " bytes");
  Serial.println("esta placa e a prova viva de que o firmware do aluno roda.");
  Serial.println();

  montarAlunos();
  montarBlocos();
  montarPerguntas();

  imprimirRoteiro();
  imprimirAlunos();
  imprimirRegraDoFeedback();
  imprimirPerguntas();
  imprimirOQueFariaDiferente();

  Serial.println("========================================");
  Serial.println(" anotacoes prontas para a lousa");
  Serial.println("========================================");
  Serial.println("alunos: " + String(totalDeAlunos) +
                 " | perguntas respondidas: " + String(perguntasRespondidas) +
                 "/" + String(totalDePerguntas));
  Serial.println("o botao avanca o LED de apresentacao a apresentacao.");
}

void loop() {
  digitalWrite(PIN_LED_STATUS, !digitalRead(PIN_LED_STATUS));

  static unsigned long ultimoToque = 0;
  if (digitalRead(PIN_BOTAO_PROXIMO) == LOW && millis() - ultimoToque > 1500) {
    ultimoToque = millis();
    Serial.println("[apresentacao] proximo aluno | heap " + String(ESP.getFreeHeap()) +
                   " B | perguntas " + String(perguntasRespondidas) + "/" +
                   String(totalDePerguntas));
  }

  Serial.println("[apresentacao] viva | v" + String(VERSAO_FIRMWARE) + " | heap " +
                 String(ESP.getFreeHeap()) + " B | LED " +
                 String(digitalRead(PIN_LED_STATUS) ? "aceso" : "apago") +
                 " | alunos " + String(totalDeAlunos));
  delay(6000);
}

Por que assim e não de outro jeito. Uma aula de apresentação não teria sketch nenhum, e essa seria a escolha óbvia: a placa não é necessária para alguém falar por quatro minutos. Ela é necessária porque o monitor serial é o instrumento de aula, e o que esta aula precisa medir é se o firmware do aluno continua rodando depois da entrega. O sketch não é exemplo de sala: ele é a mesa de som da sessão, e o que ele imprime é o que o professor anotou na lousa.

A placa não simula nada: os seis alunos, os seis projetos, os elogios e as perguntas são a lista real da turma, e o professor troca os nomes. O que importa é a estrutura do feedback, que é a mesma para todo mundo — e é por isso que a placa pode ensaiar a apresentação de alguém que ainda não apresentou.

A struct Aluno tem seis campos, e o quinto e sexto são os que estruturam a aula: a pergunta que a turma fez e a resposta que o aluno deu. O campo respondeuTudo é o que separa o que já se provou do que ainda está em aberto, e é ele que alimenta a linha de resumo no fim do setup com 2/3 — o número que o professor lê em voz alta ao encerrar.

A montagem em três funções separadas (montarAlunos, montarBlocos, montarPerguntas) não é estilo: o setup fica legível de cima a baixo, e quem vai trocar os nomes da turma não precisa ler o resto do arquivo para achar a lista. É a mesma disciplina do dia 10 aula 1, e a razão é a mesma: quem troca dado de pessoa em pessoa acaba procurando dentro de uma função de duzentas linhas.

Os blocos do roteiro são somados e impressos, e a soma aparece na tela. O professor projecta essa linha e mostra que o dia fecha em cinquenta: seis minutos de abertura, vinte e quatro de apresentações, oito de perguntas, seis de reflexão e seis de leitura das anotações. A tabela do roteiro e o que a placa imprime são o mesmo número por dois caminhos independentes, e a conferência é o critério de fim da aula.

O loop alterna o LED a cada seis segundos e imprime a placa viva com versão e heap. O que segura o botão para o cronômetro é o millis() com guarda de mil e quinhentos milissegundos, e não um delay fixo: apertar o botão quatro vezes seguidas não gera quatro linhas duplicadas, e isso importa quando o botão é o avanço de uma apresentação para a outra.

O ESP.getFreeHeap() aparece em toda linha viva, e essa é a escolha que o professor explica: o número muda ao longo da sessão, e é a prova de que a placa está viva e de que o firmware do aluno não está vazando memória. O aluno que fez o projeto de alerta com fila precisa notar que o heap dele não cai de forma geral ao longo das apresentações; se cair, o String está acumulando.

Criterios de correcao

CritérioPontos
Versão do firmware anotada e comparada com a do projeto final, com a diferença explicada se houver1 ponto
Roteiro de 4 minutos escrito e ensaiado, com o que sobra se sobrar tempo2 pontos
Apresentação feita, com a placa apontada na tela e a versão dita2 pontos
Elogio específico de um colega, citando a decisão técnica e sem "bom trabalho"2 pontos
Crítica construtiva com problema e caminho, em duas frases2 pontos
Pergunta e resposta do projeto, lidas em voz alta como se fossem respondidas2 pontos
"O que eu faria diferente" nas três partes, com o motivo em cada1 ponto

Erros comuns

ErroComo apareceCorrecao
"Bom trabalho" como elogioo aluno escreve "gostei, estava muito bom""Isso não é elogio: não diz o que foi bom e não muda o comportamento de ninguém. Nomeie a decisão — 'a consulta tem índice e página' — e diga por que ela é boa."
Elogio que elogia a pessoa, não o trabalho"você é muito dedicado""Elogio ao esforço não diz nada sobre o código. Aprova o critério é a decisão técnica que funciona, e essa é a única que o colega pode repetir no projeto dele."
Crítica só com o problema"faltou teste no seu projeto""Crítica sem caminho é só decoração. Diga o problema e onde mexer: 'o alerta dispara duas vezes porque a chave de idempotência não está na tabela — usa a chave da leitura como chave única'."
Crítica que soa como ataque"isso está errado, refaz""A ordem importa: elogio específico primeiro, para o elogio não soar como consolo; crítica depois, que precisa de elogio antes para não soar como ataque; pergunta por último."
"Não sei" como resposta completao aluno se cala depois de duas palavras"'Não sei' sem o resto é abandono. Diga o que você acharia, o que não sabe e o que precisaria ler para responder. Resposta parcial com o caminho é resposta."
Apresentar pelo código, tela a telavinte minutos mostrando arquivo"Quatro minutos é o ensaio de um produto. Mostre o que o sistema faz, mostre a decisão que importa, e cite o código como quem aponta para uma linha conhecida."
Não apontar a placa na telaa apresentação não menciona a versão"A placa subindo é a prova de que a entrega funciona. Diga a versão do firmware em voz alta — é o que separa 'entreguei um arquivo' de 'entreguei um sistema'."
Falar do projeto do colega e não do seuo aluno apresenta o deploy do colega"A apresentação é do seu projeto. Se você for apresentar o do colega como comparação, diga em uma linha por que comparou — comparação é argumento, não desvio."
Fechar sem dizer o que faltao aluno termina e a turma fica sem saber o próximo passo"Termine nomeando o que falta. Dizer 'está faltando a migração reversível' é o que permite o colega continuar depois da aula."
Elogio e crítica da mesma coisa"está bom, mas faltou índice""Elogio e crítica precisam ser de coisas diferentes. Se o índice é o problema, o elogio é outra decisão — a paginação, o log com identificador, o teste da regra."
Fingir que não tem nada a critiquearo aluno diz "não tenho nada a apontar""Todo projeto tem um 'daqui a pouco' ou um 'isso quebra quando'. Dizer qual é transforma a apresentação em conversa e é o que faz a turma aprender com o projeto do colega."
Ler o elogio da placa no modo automáticoo aluno recita a struct sem entender"A placa tem a anotação, você tem o motivo. Se você não sabe dizer por que aquele elogio é justo, o elogio não era seu — e o da placa era só exemplo."
Tremer a voz no bloco de perguntao aluno fica em silêncio e a turma espera"Pergunta sem resposta ainda é a pergunta mais útil da apresentação. Diga que vai descobrir com o código na mão e passe para a turma: alguém da turma sabe responder?"

Desafio extra

Pegue o projeto de um colega do seu grupo, com o consentimento dele, e escreva uma revisão de duas páginas com quatro partes: o que está funcionando e por quê, um defeito real com o caminho para corrigir, uma pergunta que você não soube responder, e uma sugestão de escopo para a próxima entrega. Depois devolva a ele e peça uma resposta escrita. Meça quanto tempo a revisão levou e quanto tempo ele levou para responder, e escreva uma frase sobre o que isso revela da diferença entre dar e receber crítica em trabalho de verdade.

>

A resolucao, compilada

// Aula 1 do dia 15: apresentacao dos projetos e feedback.
//
// A placa e a mesa de som da apresentacao. Enquanto cada aluno mostra o
// projeto, a placa roda o roteiro da sessao e imprime o que o professor
// anotou na lousa: o que foi demonstrado, o elogio especifico e a pergunta
// que a turma fez.
//
// Por que a placa faz parte de uma apresentacao: e o unico jeito de o
// aluno mostrar que o firmware DELE continua rodando depois de entregar. O
// monitor serial com a versao 2.0.0 e a prova viva de que a entrega nao foi
// so um arquivo.
//
// A regra de feedback que o professor escreve na lousa e a aula inteira:
// elogio especifico, critica construtiva, e uma pergunta que o aluno leva
// para casa. "Bom trabalho" nao e elogio: nao diz o que foi bom e nao muda
// o comportamento de ninguem.

#include <Arduino.h>

// Versao do firmware do aluno. O professor compara com a da lousa.
#define VERSAO_FIRMWARE "2.0.0"

#define ID_DISPOSITIVO "esp32-bancada-01"

// Quantos alunos apresentam. A turma do trimestre tem este tamanho, e o
// numero define o tempo: 4 minutos por aluno, com sobra para a duvida.
const int TOTAL_DE_ALUNOS = 6;

// Minutos por apresentacao. Com 6 alunos e 50 minutos, 4 minutos por aluno
// deixa 26 minutos de discussao, que e onde a aula vale.
const int MINUTOS_POR_APRESENTACAO = 4;

// ------------------------------------------------------------------ pinos

const int PIN_LED_STATUS = 2;
const int PIN_BOTAO_PROXIMO = 0;

// ------------------------------------------------------------------ tipos

struct Aluno {
  const char* nome;
  const char* projeto;
  const char* oQueMostrou;
  const char* elogio;
  const char* perguntaDaTurma;
  const char* respostaDoAluno;
  bool respondeuTudo;
};

struct BlocoDoDia {
  const char* quando;
  const char* oQue;
  int minutos;
};

struct Pergunta {
  const char* deQuem;
  const char* oQue;
  const char* respostaEsperada;
  bool respondida;
};

// ------------------------------------------------------------- montagem

Aluno alunos[TOTAL_DE_ALUNOS];
int totalDeAlunos = 0;

BlocoDoDia blocos[5];
int totalDeBlocos = 0;

Pergunta perguntas[3];
int totalDePerguntas = 0;
int perguntasRespondidas = 0;

void montarAlunos() {
  // Os nomes sao de exemplo: o professor troca pela lista da turma. O que
  // importa e a estrutura do feedback, que e a mesma para todo mundo.
  alunos[0].nome = "aluno 1";
  alunos[0].projeto = "estacao com login e historico";
  alunos[0].oQueMostrou = "cadastro, sessao, painel com grafico";
  alunos[0].elogio = "a consulta do historico tem indice e pagina";
  alunos[0].perguntaDaTurma = "e se a consulta estourar o tempo?";
  alunos[0].respostaDoAluno = "tem o tempo de resposta no log, e pagina de 20";
  alunos[0].respondeuTudo = true;

  alunos[1].nome = "aluno 2";
  alunos[1].projeto = "alerta de temperatura com fila";
  alunos[1].oQueMostrou = "grafico historico e alerta em tempo real";
  alunos[1].elogio = "a chave de idempotencia evitou o alerta duplo";
  alunos[1].perguntaDaTurma = "e se o broker cair?";
  alunos[1].respostaDoAluno = "a placa guarda a leitura e reenvia com a mesma chave";
  alunos[1].respondeuTudo = true;

  alunos[2].nome = "aluno 3";
  alunos[2].projeto = "portao e automacao com dois papeis";
  alunos[2].oQueMostrou = "login, painel, migracao e teste";
  alunos[2].elogio = "o README tem o passo de instalacao que funciona";
  alunos[2].perguntaDaTurma = "quem da o papel de administrador?";
  alunos[2].respostaDoAluno = "so quem ja e admin, checado no servidor";
  alunos[2].respondeuTudo = true;

  alunos[3].nome = "aluno 4";
  alunos[3].projeto = "monitor de energia com deep sleep";
  alunos[3].oQueMostrou = "medicao de consumo e tempo de bateria";
  alunos[3].elogio = "mediu antes de otimizar, e o numero esta no README";
  alunos[3].perguntaDaTurma = "quanto dura a bateria de verdade?";
  alunos[3].respostaDoAluno = "uns 30 dias no modo de sono profundo";
  alunos[3].respondeuTudo = true;

  alunos[4].nome = "aluno 5";
  alunos[4].projeto = "trilha de auditoria com log estruturado";
  alunos[4].oQueMostrou = "busca por identificador e filtro no log";
  alunos[4].elogio = "achou o erro de um dispositivo pelo id, em dois minutos";
  alunos[4].perguntaDaTurma = "e se o id for do cliente e nao do dispositivo?";
  alunos[4].respostaDoAluno = "o id propaga; o do dispositivo vai no cabecalho";
  alunos[4].respondeuTudo = false;

  alunos[5].nome = "aluno 6";
  alunos[5].projeto = "API documentada e deploy com health check";
  alunos[5].oQueMostrou = "OpenAPI, container e health check";
  alunos[5].elogio = "o health check nao consulta o banco, como deve ser";
  alunos[5].perguntaDaTurma = "e se o health check ficar verde e o banco cair?";
  alunos[5].respostaDoAluno = "a rota de dependencia responde separadamente";
  alunos[5].respondeuTudo = true;

  totalDeAlunos = 6;
}

void montarBlocos() {
  blocos[0].quando = "0 a 6 min";
  blocos[0].oQue = "abertura: o que a turma construiu em 30 aulas";
  blocos[0].minutos = 6;

  blocos[1].quando = "6 a 30 min";
  blocos[1].oQue = "as 6 apresentacoes, 4 minutos cada";
  blocos[1].minutos = 24;

  blocos[2].quando = "30 a 38 min";
  blocos[2].oQue = "as 3 perguntas da turma, uma por aluno sorteado";
  blocos[2].minutos = 8;

  blocos[3].quando = "38 a 44 min";
  blocos[3].oQue = "o que eu faria diferente, lido em voz alta";
  blocos[3].minutos = 6;

  blocos[4].quando = "44 a 50 min";
  blocos[4].oQue = "o professor le as anotacoes da placa, uma por uma";
  blocos[4].minutos = 6;

  totalDeBlocos = 5;
}

void montarPerguntas() {
  perguntas[0].deQuem = "aluno 1";
  perguntas[0].oQue = "qual camada do seu projeto demorou mais e por que";
  perguntas[0].respostaEsperada = "o banco, porque a migracao foi feita depois da regra";
  perguntas[0].respondida = true;

  perguntas[1].deQuem = "aluno 4";
  perguntas[1].oQue = "qual numero voce mediu antes de escolher o deep sleep";
  perguntas[1].respostaEsperada = "o consumo em modo acordada, em microamperes";
  perguntas[1].respondida = true;

  perguntas[2].deQuem = "aluno 5";
  perguntas[2].oQue = "o que faltou responder da sua pergunta da turma";
  perguntas[2].respostaEsperada = "a propagacao do id no log, que ele vaia implementar";
  perguntas[2].respondida = false;

  totalDePerguntas = 3;
  perguntasRespondidas = 2;
}

// ------------------------------------------------------------------ saida

void imprimirRoteiro() {
  Serial.println("========================================");
  Serial.println(" o roteiro da sessao");
  Serial.println("========================================");
  int soma = 0;
  for (int i = 0; i < totalDeBlocos; i++) {
    Serial.println("  " + String(blocos[i].quando) + " | " +
                   String(blocos[i].minutos) + " min | " + String(blocos[i].oQue));
    soma += blocos[i].minutos;
  }
  Serial.println();
  Serial.println("soma: " + String(soma) + " min | por aluno: " +
                 String(MINUTOS_POR_APRESENTACAO) + " min");
  Serial.println();
}

void imprimirAlunos() {
  Serial.println("========================================");
  Serial.println(" quem apresenta o que");
  Serial.println("========================================");
  for (int i = 0; i < totalDeAlunos; i++) {
    Serial.println();
    Serial.println("  " + String(alunos[i].nome) + " — " + String(alunos[i].projeto));
    Serial.println("    mostrou: " + String(alunos[i].oQueMostrou));
    Serial.println("    elogio:  " + String(alunos[i].elogio));
    Serial.println("    pergunta: " + String(alunos[i].perguntaDaTurma));
    Serial.println("    resposta: " + String(alunos[i].respostaDoAluno));
  }
  Serial.println();
}

void imprimirRegraDoFeedback() {
  Serial.println("========================================");
  Serial.println(" a regra do feedback, em tres partes");
  Serial.println("========================================");
  Serial.println();
  Serial.println("1. ELOGIO ESPECIFICO");
  Serial.println("   'a consulta do historico tem indice e pagina'");
  Serial.println("   'bom trabalho' nao e elogio: nao diz o que foi bom e nao");
  Serial.println("   muda o comportamento de ninguem. elogio generico e o mesmo");
  Serial.println("   que elogio nenhum, so que com palavras a mais.");
  Serial.println();
  Serial.println("2. CRITICA CONSTRUTIVA");
  Serial.println("   'o health check consulta o banco' + 'tire essa consulta e");
  Serial.println("   faca a dependencia aparecer em outra rota'");
  Serial.println("   critica sem caminho e so quedacao. o caminho e o que faz a");
  Serial.println("   critica ser util.");
  Serial.println();
  Serial.println("3. UMA PERGUNTA QUE FICA");
  Serial.println("   'e se a consulta estourar o tempo?'");
  Serial.println("   pergunta e o que o aluno leva para casa. elogio e o que o");
  Serial.println("   aluno ja sabe; pergunta e o que ele ainda nao sabe.");
  Serial.println();
  Serial.println("a ordem importa: elogio especifico primeiro, para o elogio");
  Serial.println("nao soar como consolo; depois a critica, que precisa de um");
  Serial.println("elogio antes para nao soar como ataque; depois a pergunta.");
  Serial.println();
}

void imprimirPerguntas() {
  Serial.println("========================================");
  Serial.println(" as perguntas da turma");
  Serial.println("========================================");
  for (int i = 0; i < totalDePerguntas; i++) {
    Serial.println();
    Serial.println("  " + String(perguntas[i].deQuem) + " pergunta: " +
                   String(perguntas[i].oQue));
    Serial.println("    resposta esperada: " + String(perguntas[i].respostaEsperada));
    Serial.println("    respondida: " + String(perguntas[i].respondida ? "sim" : "NAO"));
  }
  Serial.println();
  Serial.println("respondidas: " + String(perguntasRespondidas) + " de " +
                 String(totalDePerguntas));
  Serial.println();
  Serial.println("a pergunta nao respondida nao e falta do aluno: e a que");
  Serial.println("ele vai descobrir em casa, com o codigo na mao. o professor");
  Serial.println("anota na lousa e cobra na proxima aula, se a turma voltar.");
  Serial.println();
}

void imprimirOQueFariaDiferente() {
  Serial.println("========================================");
  Serial.println(" o que eu faria diferente");
  Serial.println("========================================");
  Serial.println("o professor pede esta parte em voz alta, para a turma inteira.");
  Serial.println("serve para duas coisas: mostra que o professor tambem teve");
  Serial.println("projeto com defeito, e mostra o formato de uma resposta util.");
  Serial.println();
  Serial.println("  1. o que eu trocaria no MEU projeto");
  Serial.println("     'eu comecaria pelo teste da regra, e nao pela migration'");
  Serial.println();
  Serial.println("  2. o que eu aprendi com o projeto de voces");
  Serial.println("     'a duvida real de vcs foi de escopo, e nao de sintaxe'");
  Serial.println();
  Serial.println("  3. o que eu levaria para o proximo ano");
  Serial.println("     'mais tempo em migration, que e onde a turma mais travou'");
  Serial.println();
  Serial.println("resposta em tres frases, com nome proprio e com o motivo.");
  Serial.println("'faria diferente' sem o motivo e so o 'faria diferente'");
  Serial.println("com mais palavras.");
  Serial.println();
}

// ---------------------------------------------------------------- setup

void setup() {
  Serial.begin(115200);
  delay(300);

  pinMode(PIN_LED_STATUS, OUTPUT);
  pinMode(PIN_BOTAO_PROXIMO, INPUT_PULLUP);
  digitalWrite(PIN_LED_STATUS, HIGH);

  Serial.println();
  Serial.println("========================================");
  Serial.println(" apresentacao dos projetos — v" + String(VERSAO_FIRMWARE));
  Serial.println("========================================");
  Serial.println("dispositivo do aluno: " + String(ID_DISPOSITIVO));
  Serial.println("cpu: " + String(getCpuFrequencyMhz()) + " MHz | heap: " +
                 String(ESP.getFreeHeap()) + " bytes");
  Serial.println("esta placa e a prova viva de que o firmware do aluno roda.");
  Serial.println();

  montarAlunos();
  montarBlocos();
  montarPerguntas();

  imprimirRoteiro();
  imprimirAlunos();
  imprimirRegraDoFeedback();
  imprimirPerguntas();
  imprimirOQueFariaDiferente();

  Serial.println("========================================");
  Serial.println(" anotacoes prontas para a lousa");
  Serial.println("========================================");
  Serial.println("alunos: " + String(totalDeAlunos) +
                 " | perguntas respondidas: " + String(perguntasRespondidas) +
                 "/" + String(totalDePerguntas));
  Serial.println("o botao avanca o LED de apresentacao a apresentacao.");
}

void loop() {
  digitalWrite(PIN_LED_STATUS, !digitalRead(PIN_LED_STATUS));

  static unsigned long ultimoToque = 0;
  if (digitalRead(PIN_BOTAO_PROXIMO) == LOW && millis() - ultimoToque > 1500) {
    ultimoToque = millis();
    Serial.println("[apresentacao] proximo aluno | heap " + String(ESP.getFreeHeap()) +
                   " B | perguntas " + String(perguntasRespondidas) + "/" +
                   String(totalDePerguntas));
  }

  Serial.println("[apresentacao] viva | v" + String(VERSAO_FIRMWARE) + " | heap " +
                 String(ESP.getFreeHeap()) + " B | LED " +
                 String(digitalRead(PIN_LED_STATUS) ? "aceso" : "apago") +
                 " | alunos " + String(totalDeAlunos));
  delay(6000);
}

Sem saída de compilação gravada. Rode python3 validar.py -t 3 dia15 aula1.

Aula 2 — Encerramento do ano e o passo depois

Objetivos

letivo` entregou, camada por camada, sem olhar para o caderno.

  • Conferir no inventário de material quais peças quebraram e quais faltaram comprar, e separar as duas coisas.
  • Ordenar as sugestões de mudança para o próximo ano por prioridade, com o motivo junto.
  • Calcular o custo de abrir uma vaga na turma, e explicar por que esse número não é o custo do material.
  • Escrever a próxima etapa com prazo, e dizer o que a continuidade do curso significa para quem não volta.

Material

  • 1 ESP32 DevKit V1 por aluno, com o cabo USB, na bancada para a conferência final
  • 1 botao com pull-up no pino 0, que imprime a placa de encerramento com a data da gravação
  • O inventário do laboratório escrito à mão, com a coluna de situação de cada peça
  • Folha por aluno com as quatro sugestões de mudança, para assinar no fim da aula
  • Monitor serial a 115200, aberto na tela do projetor durante a leitura das anotações

Conceitos

O que fecha: as sete camadas e a pergunta que separa quem fez o curso

O encerramento de um curso é a aula em que o professor faz a única coisa que a sequência inteira preparou: somar. E a soma não é a lista de conteúdos — é a pergunta que atravessa todas as camadas.

O sketch imprime sete camadas com a marca de entregue, e sete de sete é o número que o professor projeta:

CamadaO que entregou
hardwaresensor, display e saída digital, com fiação certa
firmwareC++ que compila, com tempo limite e log
redeWiFi que reconecta, HTTP com código de status
servidorNode com login, sessão, permissão e log com identificador
bancoMySQL com repository, migração e paginação
entregateste, segurança, deploy e README que roda
projeto finalsistema completo, apresentado e revisado

A pergunta que o professor faz ao encerrar é uma só, e é a que divide a turma: onde o dado começa e onde ele termina. Quem responde "no DHT11 e termina na linha do MySQL, passando pelo painel" fez o curso. Quem responde "no ESP32" parou na metade, e essa metade é a que serve para a bancada e não para produto.

O ciclo que fecha é o ano letivo: treze dias no primeiro trimestre, dezesseis no segundo e quinze no terceiro, com duas aulas por semana. É um número de calendário, e ele importa por um motivo pequeno e concreto: ele é a medida do que cabe em um curso com professor e com bancada. Quem planeja o próximo curso precisa desse número como limite, não como estimativa.

O inventário: o que quebrou é dado, não azar

A parte que o professor diz que é a lista mais útil do ano não vai para o portal do aluno: é o inventário de material. Peça por peça, com a situação real e a marca de precisa comprar ou não.

O inventário do laboratório é o que separa material que faltou de kit que quebrou, e a distinção é a primeira coisa que o professor ensina antes de ler a lista. As duas frases da atividade do ano aparecem separadas na placa, e é essa separação que muda o que a coordenação compra:

SituaçãoFrase da placaO que ela significa
kit que quebrou"funcionando, 2 com o cabo frouxo"a peça estava no armário e deixou de funcionar
material que faltou"faltaram 3 kits, repuser do armário"nunca houve peça suficiente para a turma

O que comprar sai dessas duas frases juntas, e por isso a lista da placa tem uma coluna só — precisaComprar — mas as situações são narradas de maneiras diferentes. O professor aponta essa diferença e pede que a turma não misture: dizer que "faltou DHT11" quando o que houve foram dois DHT11 que falharam muda a decisão de compra no mesmo orçamento.

O que a placa imprime tem seis itens, e o professor comenta os três que mudam a decisão:

ItemSituaçãoComprar
ESP32 DevKit V112, funcionando, 2 com o cabo frouxosim
cabo USB12, funcionando, 1 na trocasim
DHT1112, 2 falhando, leitura travada em 0sim
display OLED com I2C12, funcionando, 1 com cabo solto no VCCnão
jumpersfaltaram 3 kits, repuser do armáriosim
fonte de bancada1, queimou em março, falta reposiçãosim

O display está na lista com não precisa comprar, e essa linha é o exemplo que o professor usa: uma peça com defeito não é automaticamente peça para comprar. O cabo solto se resolve com o cabo, e o cabo está na lista. Quem compra peça porque viu uma com defeito gasta dinheiro dobrado.

E o item que mais custa não é o mais caro: é a fonte de bancada que queimou em março. Uma peça quebrada é uma placa fora de uso; a fonte é a bancada inteira fora de uso, e a próxima turma não começa sem ela. Por isso a ordem da compra é o que o professor leva para a coordenação, e não a lista.

O custo real de abrir uma vaga, e a mudança que vem depois

A placa imprime o custo do kit por aluno e a conta da turma, e o professor usa os dois números para dizer a mesma coisa de duas maneiras. O CUSTO_DO_KIT_POR_ALUNO de R$ 145,00 é o que a escola gasta em material por aluno. A conta da turma de doze é esse número multiplicado.

E o número que importa é outro, e é o que o professor dita duas vezes para que ninguém anote o primeiro: o custo real de uma vaga aberta é o de uma placa que quebrou na semana 3 e o que a aula não virou naquele dia. Uma placa que parou custou o material e custou a aula — e a aula repetida custa a turma inteira de novo. Material é a parte mensurável; aula perdida é a parte que não aparece em nota fiscal e é a que dói.

Por isso a sugestão de comprar um kit de reserva vem antes de comprar sensor novo: o sensor custa vinte reais e a placa reserva evita a repetição de uma aula. O critério é o custo de indisponibilidade, e ele é sempre maior que o preço da peça.

E é do custo de uma aula perdida que saem as melhorias para o próximo ano, que são quatro, com o professor projetando a coluna de prioridade com a mesma força com que projeta as notas:

PrioridadeMudançaPor quê
1aumentar a aula de migração para duasa turma mais travou em migration, não em sintaxe
1comprar um kit de reserva antes de comprar sensorplaca que quebra para a aula inteira, sensor custa vinte reais
2guardar os 3 kits de jumper no armário com etiquetafaltou material três vezes no mesmo trimestre
2começar o segundo trimestre com revisão de 1 aulaquem entrou depois da semana 2 não acompanhou a camada de rede

A separação é o que dá valor à lista: prioridade 1 muda o ano, e prioridade 2 só tira trabalho. Uma lista de dez itens sem prioridade é reclamação; uma lista de quatro com duas marcadas é plano.

E o porquê é o que transforma sugestão de melhoria em dado. "Aumentar a aula de migração" é opinião; "a turma mais travou em migration, não em sintaxe" é observação, e observação é o que o professor consegue defender na coordenação sem ter que convencer ninguém de nada. A pergunta que o professor faz à turma antes de ler a lista em voz alta é: em que assunto vocês mais travaram? E a resposta que a turma dá é, quase sempre, a mesma que a lista já tem.

O encerramento: o ciclo fecha, a continuidade não

O encerramento do ano letivo tem duas metades, e confundi-las é o erro mais comum de quem escreve a própria despedida.

A primeira metade é o ciclo que fecha: as aulas dadas, as camadas entregues, o inventário conferido, as sugestões anotadas. Nada disso volta, e é exatamente por isso que precisa ser escrito — a memória de um curso é pior que a memória de um banco, e o banco tem índice.

A segunda metade é a próxima etapa, e ela é do aluno, não da escola. A continuidade do curso é o que continua depois da última aula: o projeto pessoal publicado, a sequência de três passos do plano de noventa dias, e a próxima turma que recebe o mesmo kit com as correções desta lista aplicadas. Quem tem as três coisas com data continua; quem tem "quando der" não começa nada, e o professor diz isso olhando para a turma e não para a lousa.

O que fica na placa é a última versão gravada, com a data e a hora da gravação, e é o registro do ano: quando o laboratório for aberto de novo, o monitor serial mostra qual era a última entrega. Um obrigado verdadeiro não precisa de placa nenhuma — e o professor diz o dele em voz alta, sem ler da tela, porque é a única coisa da aula que não é conteúdo.

Atividade

Montagem: botao com pull-up no pino 0 para imprimir a placa de encerramento, jumper de saída no pino 2 para o LED de status, ground no GND. A placa fica na bancada durante a leitura das listas, e a última versão gravada é a que fica no arquivo do laboratório.

  1. Grave o sketch da resolução e rode no serial. Anote os três números da primeira seção: trimestres, dias letivos e aulas. Eles batem com o calendário que a escola imprimiu? Multiplique os dias pelas duas aulas e confira o total: o número que a placa imprime é o mesmo que a sua conta dá?
  2. Na lista das sete camadas, conte quantas têm a marca de entregue. Qual camada, se alguma, você não acha que ficou? Escreva o que falta para ela ficar.
  3. Pegue o inventário escrito à mão e compare com o que a placa imprimiu. Bate? Marque a diferença, se houver — e diga se o erro foi de lista ou de memória.
  4. Escreva o custo de abrir uma vaga nova, em duas partes: o que é material e o que é aula perdida. Qual das duas partes é maior, e por que essa não aparece na nota fiscal?
  5. Ordene as quatro sugestões com as suas próprias palavras. As duas de prioridade um mudam o ano ou só tiram trabalho? Justifique a ordem em duas frases.
  6. Escreva a próxima etapa com prazo: uma data, uma coisa e um número de horas. Anote a data. Se a sua data é "quando der", escreva isso e diga o que precisa mudar para ela virar uma data.
  7. Em uma frase, diga o que a próxima turma recebe de você e de mim, além do material. Guarde essa frase: ela é a última do ano.

Nota: 12 pontos. Critério de fim: o inventário conferido contra a lista da placa, e a próxima etapa escrita com data e horas.

Resolucao

// Aula 2 do dia 15: encerramento do ano e o passo depois.
//
// Ultima aula do ano. Nao ha codigo novo para aprender e nao ha prova: ha
// um ciclo fechando e duas perguntas que so o titular pode responder.
//
// A placa faz o fechamento contábil do ano. Ela conta o que o ciclo entregou
// (as 30 aulas, os 15 dias, as 3 trilhas), e ela recolhe o que faltou — o
// inventário de material, que e a parte que o professor leva para a
// coordinate e que costuma ser ignorada.
//
// Os dois blocos que o professor precisa ler em voz alta:
//
//   1. O QUE FECHOU: o ciclo que fecha, o que a turma entregou, e o numero
//      que responde "valeu a pena".
//   2. O QUE FALTOU: o material que quebrou, o que faltou comprar, e as
//      tres sugestoes de mudanca que mudam o ano que vem.
//
// A segunda lista e a que o professor vai agradecer. E a unica aula do ano
// em que o aluno escreve no codigo, e a escrita e sobre a escola, nao sobre
// o firmware.

#include <Arduino.h>

// Versao do firmware. Ultima gravacao do ano: e o que fica na placa quando
// a turma toda apagada e o laboratorio fecha.
#define VERSAO_FIRMWARE "2.0.0"

#define ID_DISPOSITIVO "esp32-bancada-01"

// ------------------------------------------------------------------ pinos

const int PIN_LED_STATUS = 2;
const int PIN_BOTAO_FECHAMENTO = 0;

// -------------------------------------------------------------- configuracao

// Numero de aulas do ano. Soma dos tres trimestres do eixo: 13 + 16 + 15
// dias, com 2 aulas por dia. O numero e medido no eixo, nao escolhido.
const int DIAS_DO_ANO = 44;
const int TOTAL_DE_AULAS_DO_ANO = 88;
const int TRIMESTRES = 3;

// Custo do material, em reais. Valor de referencia do kit da bancada, e o
// que o professor usa para calcular quanto custa matricular um aluno novo.
const float CUSTO_DO_KIT_POR_ALUNO = 145.00;

// ------------------------------------------------------------------ tipos

struct OQueFechou {
  const char* item;
  const char* como;
  bool entregue;
};

struct Material {
  const char* item;
  const char* situacao;
  int quantidade;
  bool precisaComprar;
};

struct Sugestao {
  const char* mudanca;
  const char* porque;
  int prioridade;
};

// --------------------------------------------------------------- montagem

OQueFechou fechamento[7];
int totalDoFechamento = 0;

Material materiais[6];
int totalDeMateriais = 0;

Sugestao sugestoes[4];
int totalDeSugestoes = 0;

void montarFechamento() {
  fechamento[0].item = "a camada de hardware";
  fechamento[0].como = "sensor, display e saida digital, com fiaçao certa";
  fechamento[0].entregue = true;

  fechamento[1].item = "a camada de firmware";
  fechamento[1].como = "C++ que compila, com tempo limite e log";
  fechamento[1].entregue = true;

  fechamento[2].item = "a camada de rede";
  fechamento[2].como = "WiFi que reconecta, HTTP com codigo de status";
  fechamento[2].entregue = true;

  fechamento[3].item = "a camada de servidor";
  fechamento[3].como = "Node com login, sessao, permissao e log com id";
  fechamento[3].entregue = true;

  fechamento[4].item = "a camada de banco";
  fechamento[4].como = "MySQL com repository, migracao e paginacao";
  fechamento[4].entregue = true;

  fechamento[5].item = "a camada de entrega";
  fechamento[5].como = "teste, seguranca, deploy e README que roda";
  fechamento[5].entregue = true;

  fechamento[6].item = "o projeto final";
  fechamento[6].como = "sistema completo, apresentado e revisado";
  fechamento[6].entregue = true;

  totalDoFechamento = 7;
}

void montarMateriais() {
  materiais[0].item = "ESP32 DevKit V1";
  materiais[0].situacao = "funcionando, 2 com o cabo frouxo";
  materiais[0].quantidade = 12;
  materiais[0].precisaComprar = true;

  materiais[1].item = "cabo USB";
  materiais[1].situacao = "funcionando, 1 na troca";
  materiais[1].quantidade = 12;
  materiais[1].precisaComprar = true;

  materiais[2].item = "DHT11";
  materiais[2].situacao = "2 falhando, leitura travada em 0";
  materiais[2].quantidade = 12;
  materiais[2].precisaComprar = true;

  materiais[3].item = "display OLED I2C";
  materiais[3].situacao = "funcionando, 1 com cabo solto no VCC";
  materiais[3].quantidade = 12;
  materiais[3].precisaComprar = false;

  materiais[4].item = "jumpers";
  materiais[4].situacao = "faltaram 3 kits, repuser do armario";
  materiais[4].quantidade = 12;
  materiais[4].precisaComprar = true;

  materiais[5].item = "fonte de bancada";
  materiais[5].situacao = "1 queimou em marco, falta reposicao";
  materiais[5].quantidade = 1;
  materiais[5].precisaComprar = true;

  totalDeMateriais = 6;
}

void montarSugestoes() {
  sugestoes[0].mudanca = "aumentar a aula de migracao para duas";
  sugestoes[0].porque = "a turma mais travou em migration, nao em sintaxe";
  sugestoes[0].prioridade = 1;

  sugestoes[1].mudanca = "comprar um kit de reserva antes de comprar sensor";
  sugestoes[1].porque = "placa que quebra para a aula inteira, sensor e 20 reais";
  sugestoes[1].prioridade = 1;

  sugestoes[2].mudanca = "guardar os 3 kits de jumper no armario com etiqueta";
  sugestoes[2].porque = "faltou material 3 vezes no mesmo trimestre";
  sugestoes[2].prioridade = 2;

  sugestoes[3].mudanca = "comecar o segundo trimestre com revisao de 1 aula";
  sugestoes[3].porque = "quem entrou depois da semana 2 nao acompanhou a camada de rede";
  sugestoes[3].prioridade = 2;

  totalDeSugestoes = 4;
}

// ------------------------------------------------------------------ saida

void imprimirContagem() {
  Serial.println("========================================");
  Serial.println(" o ano em numeros");
  Serial.println("========================================");
  Serial.println("trimestres:     " + String(TRIMESTRES) + " (13 + 16 + 15 dias)");
  Serial.println("aulas:          " + String(TOTAL_DE_AULAS_DO_ANO) + " (" +
                 String(DIAS_DO_ANO) + " dias de 2)");
  Serial.println("firmware:       versao " + String(VERSAO_FIRMWARE));
  Serial.println("cpu:            " + String(getCpuFrequencyMhz()) + " MHz");
  Serial.println("heap:           " + String(ESP.getFreeHeap()) + " bytes");
  Serial.println();
}

void imprimirOQueFechou() {
  Serial.println("========================================");
  Serial.println(" 1. o que este ciclo entregou");
  Serial.println("========================================");
  int entregues = 0;
  for (int i = 0; i < totalDoFechamento; i++) {
    if (fechamento[i].entregue) entregues++;
    Serial.println("  [" + String(fechamento[i].entregue ? "x" : " ") + "] " +
                   String(fechamento[i].item) + " — " + String(fechamento[i].como));
  }
  Serial.println();
  Serial.println("entregues: " + String(entregues) + " de " + String(totalDoFechamento));
  Serial.println();
  Serial.println("a camada que oano juntou e a que responde a pergunta 'onde");
  Serial.println("o dado comeca e onde ele termina'. Um aluno que sabe dizer");
  Serial.println("isso sem olhar para o diagrama fez o ano.");
  Serial.println();
}

void imprimirCusto() {
  Serial.println("========================================");
  Serial.println(" quanto custa uma vaga aberta");
  Serial.println("========================================");
  Serial.println("kit por aluno:   R$ " + String(CUSTO_DO_KIT_POR_ALUNO, 2));
  Serial.println("turma de 12:     R$ " + String(CUSTO_DO_KIT_POR_ALUNO * 12, 2));
  Serial.println("a comprar de novo:");
  int paraComprar = 0;
  for (int i = 0; i < totalDeMateriais; i++) {
    if (materiais[i].precisaComprar) paraComprar++;
  }
  Serial.println("  itens:         " + String(paraComprar) + " de " + String(totalDeMateriais));
  Serial.println();
  Serial.println("a conta que o titular faz nao e o custo do material: e o");
  Serial.println("custo de uma placa que quebrou na semana 3 e o que a aula");
  Serial.println("nao virou naquele dia. Por isso a reserva vem primeiro.");
  Serial.println();
}

void imprimirInventario() {
  Serial.println("========================================");
  Serial.println(" 2. o material: o que quebrou, o que faltou");
  Serial.println("========================================");
  for (int i = 0; i < totalDeMateriais; i++) {
    Serial.println();
    Serial.println("  " + String(materiais[i].item) + " (x" +
                   String(materiais[i].quantidade) + ")");
    Serial.println("    situacao: " + String(materiais[i].situacao));
    Serial.println("    comprar: " + String(materiais[i].precisaComprar ? "SIM" : "nao"));
  }
  Serial.println();
  Serial.println("esta e a lista que o professor leva para a coordenacao.");
  Serial.println("ela nao vai para o portal do aluno: sao problemas internos");
  Serial.println("da escola, e o aluno nao tem o que fazer com isso.");
  Serial.println();
}

void imprimirSugestoes() {
  Serial.println("========================================");
  Serial.println(" as sugestoes para o proximo ano");
  Serial.println("========================================");
  for (int i = 0; i < totalDeSugestoes; i++) {
    Serial.println();
    Serial.println("  prioridade " + String(sugestoes[i].prioridade) + ": " +
                   String(sugestoes[i].mudanca));
    Serial.println("    porque: " + String(sugestoes[i].porque));
  }
  Serial.println();
  Serial.println("prioridade 1 e o que muda o ano; prioridade 2 e o que so");
  Serial.println("tira trabalho. A ordem importa: comprar jumper antes de");
  Serial.println("mudar o conteudo e o que o aluno sente na aula.");
  Serial.println();
}

void imprimirEncerramento() {
  Serial.println("========================================");
  Serial.println(" 3. encerramento");
  Serial.println("========================================");
  Serial.println("o ciclo fecha aqui, e a placa fica na bancada com a ultima");
  Serial.println("gravacao. A proxima turma recebe o mesmo kit e o mesmo");
  Serial.println("material, so que com as correcoes desta lista aplicadas.");
  Serial.println();
  Serial.println("obrigado: a placa imprime uma vez por boot, e o professor");
  Serial.println("nao precisa ler a palavra para dizer a de verdade.");
  Serial.println();
  Serial.println("a proxima etapa e continuar estudando, com projeto proprio");
  Serial.println("e com a sequencia de ports: firmware, depois servidor, depois");
  Serial.println("os dois juntos. O ano que vem comeca onde este terminou.");
  Serial.println();
}

// ---------------------------------------------------------------- setup

void setup() {
  Serial.begin(115200);
  delay(400);

  pinMode(PIN_LED_STATUS, OUTPUT);
  pinMode(PIN_BOTAO_FECHAMENTO, INPUT_PULLUP);
  digitalWrite(PIN_LED_STATUS, HIGH);

  Serial.println();
  Serial.println("========================================");
  Serial.println("========================================");
  Serial.println(" FIM DO ANO LETIVO — v" + String(VERSAO_FIRMWARE));
  Serial.println("========================================");
  Serial.println("========================================");
  Serial.println("dispositivo: " + String(ID_DISPOSITIVO) + " | ultima gravacao do ano");
  Serial.println();

  montarFechamento();
  montarMateriais();
  montarSugestoes();

  imprimirContagem();
  imprimirOQueFechou();
  imprimirCusto();
  imprimirInventario();
  imprimirSugestoes();
  imprimirEncerramento();

  Serial.println("========================================");
  Serial.println(" placa de encerramento ligada e respondendo");
  Serial.println("========================================");
}

void loop() {
  // A placa fica viva ate o fim do periodo letivo. Nao e preciso manter
  // isso ligado, e o que importa e o registro: a ultima versao gravada
  // e a que fica no historico do laboratorio.
  digitalWrite(PIN_LED_STATUS, !digitalRead(PIN_LED_STATUS));

  if (digitalRead(PIN_BOTAO_FECHAMENTO) == LOW) {
    static unsigned long ultimoToque = 0;
    if (millis() - ultimoToque > 2000) {
      ultimoToque = millis();
      Serial.println();
      Serial.println("========================================");
      Serial.println(" ate a proxima");
      Serial.println("========================================");
      Serial.println("dispositivo: " + String(ID_DISPOSITIVO) + " v" + String(VERSAO_FIRMWARE));
      Serial.println("firmware gravado em: " + String(__DATE__) + " as " + String(__TIME__));
      Serial.println("heap: " + String(ESP.getFreeHeap()) + " bytes | cpu: " +
                     String(getCpuFrequencyMhz()) + " MHz");
      Serial.println("========================================");
      Serial.println();
    }
  }

  Serial.println("[fim do ano] viva | v" + String(VERSAO_FIRMWARE) + " | heap " +
                 String(ESP.getFreeHeap()) + " B | LED " +
                 String(digitalRead(PIN_LED_STATUS) ? "aceso" : "apago"));
  delay(9000);
}

Por que assim e não de outro jeito. A última aula do ano não tem código para aprender, e o esqueleto óbvio seria um sketch vazio com um "obrigado". A placa faz o fechamento contábil do ano, e a escolha é deliberada: as três listas que o professor precisa ler em voz alta saem da placa, e não da memória dele. Memória de professor erra número; a lista impressa não.

O primeiro bloco é a contagem, e ele vem antes de tudo porque é o que dá escala ao resto: três trimestres, quarenta e quatro dias, oitenta e oito aulas. O __DATE__ e o __TIME__ no fim do loop são a prova de que o ano tem data, e não só número.

E aqui está a armadilha do número, que o professor aponta em voz alta antes de qualquer coisa: a conta de 15 × 2 × 3 = 90 não fecha. Trimestre não tem quinze dias cada — o primeiro tem treze, o segundo tem dezesseis e o terceiro tem quinze. Quem escreve 90 no slide está contando dias que não existem, e o aluno que conferir o eixo descobre. Número inventado é erro de regra, e a última aula do curso é o único lugar do ano em que o aluno audita a conta do professor.

A segunda lista é o que este ciclo entregou, e o campo entregue é um bool por item. Ele não está ali por decoração: o professor marca o que não fechou, se alguma camada não fechou, e o contador soma. Sete de sete é o número de hoje; se fosse seis de sete, o Serial diria seis de sete sem que ninguém precisasse contar, e é essa automatização boba que evita a constante "entregues?" da conversa.

O terceiro bloco é a lista que vai para a coordenação, e ele é o inverso do anterior: as sete camadas são para a turma e o inventário é para a escola. A placa separa os dois porque eles têm leitores diferentes, e o aluno não tem o que fazer com a informação de que a fonte queimou em março. A linha do Serial que diz isso na tela é a que o professor lê antes de guardá-la.

O CUSTO_DO_KIT_POR_ALUNO é um float, e a conta da turma é a multiplicação dele por doze. O professor explica por que float e não int em reais: os centavos existem, e um inteiro de reais arredonda o custo por aluno sem que ninguém perceba. A saída usa String com duas casas para o valor, que é a diferença entre "R$ 145" e "R$ 145,00" no orçamento que vai para a coordenação.

O contador de itens a comprar é feito com uma passada no vetor, e não com um número escrito à mão. Isso é a mesma disciplina do dia 5: quem escreve o total à mão erra quando alguém corrige a lista no meio do trimestre, e o erro fica na placa até o fim do ano.

O loop imprime a placa viva e, no botão, imprime a data e a hora da gravação com __DATE__ e __TIME__. Esses dois macros são resolvidos quando o firmware é compilado, e o professor explica que por isso eles dizem quando o professor gravou, e não quando a placa acordou — a diferença importa quando alguém quiser saber de quando é a imagem que está rodando naquele poste.

A resolução fecha lembrando que a placa não precisa ficar ligada: o que importa é o registro, e a última versão gravada é a que fica no arquivo do laboratório. Manter doze placas ligadas durante o recesso é custo sem retorno.

Criterios de correcao

CritérioPontos
Três números da contagem anotados e comparados com o calendário da escola2 pontos
Camadas entregues contadas, e a camada que falta escrita com o que falta para ela fechar2 pontos
Inventário conferido contra a lista da placa, com a diferença nomeada2 pontos
Custo da vaga escrito nas duas partes, com o maior número identificado2 pontos
Quatro sugestões ordenadas com as suas palavras, com a prioridade justificada2 pontos
Próxima etapa com data, uma coisa e horas1 ponto
Última frase escrita sobre o que a próxima turma recebe1 ponto

Erros comuns

ErroComo apareceCorrecao
"Faltou material" como desculpa para a baixa presençaa turma não assistiu e o nome da peça some da conversa"Falta de material é um dado, e a placa tem a lista. Mas ausência de aluno não sai de peça quebrada — e transformar tudo em falha de material tira do aluno a parte que é dele."
Comprar peça porque uma com defeito apareceuo professor volta com dois displays novos e um cabo velho ainda na bancada"Peça com defeito não é peça para comprar se o defeito é no cabo. Resolva o cabo antes. Comprar antes de diagnosticar é o erro do dia 11 aplicado ao armário."
Contar material como custo da vagao orçamento da coordenação usa só o número do kit"O custo do material é a parte fácil. A cara é a placa que quebrou na semana 3 e a aula que não virou. Esse número não aparece em nota fiscal e é o que a coordenação precisa ouvir."
Lista de sugestões sem prioridadedez itens em ordem aleatória"Sem prioridade, a lista é reclamação. Duas marcadas mudam o ano; o resto só tira trabalho. Quatro itens com duas marcadas valem mais que dez sem nenhuma."
Mudança de conteúdo antes de mudança de materiala lista começa por "aumentar a aula de migration" e o jumper some"Ordem importa. O jumper que faltou tirou três kits de aula: o aluno sente isso no dia. A aula de migração é prioridade um, mas a segunda lista é o que a turma sente primeiro."
Escrever "obrigado" e encerrar sem perguntao aluno não sabe se pode perguntar nada depois"Encerramento não é dispensa. Deixe a pergunta aberta e aceite a dúvida que aparecer na próxima turma, mesmo que seja sobre coisa já dada."
Prometer material para a turma sem comprar anteso professor anuncia um kit que não existe no armário"Promessa de material é dívida. Se não está comprado, não anuncia. Aluno que chega e não tem o que foi prometido aprende que anúncio não vale nada."
Plano do aluno sem data"vou publicar quando eu conseguir""Sem data, não é plano. Escreva uma data e um número de horas. 'Quando conseguir' é o mesmo que não fazer, escrito com otimismo."
Plano com prazo mas sem horas"semana que vem, umas horas""Horas é o que protege o prazo. Vinte e cinco horas cabem em duas semanas; 'umas horas' não cabe em prazo nenhum."
Dizer que não falta nadao aluno monta a lista e nenhuma sugestão tem prioridade 1"Quem não encontra nada para mudar no próprio ano não olhou. Alguém da turma sempre tem uma sugestão que você não tinha pensado — peça, não assuma."
Levar o inventário para a aula do alunoo aluno passa o ano inteiro lendo sobre a fonte queimada"A lista de material é problema da escola, e fica com a escola. O aluno precisa de um inventário de habilidade, que é a aula de ontem."
Tratar o encerramento como repetiçãoo professor repete a última aula do dia 13 e chama de despedida"Encerrar é somar, não repetir. Se a última aula é conteúdo novo, o curso não fechou — faltou a semana que fecha."
Deixar a placa gravada sem ler nadaa placa fica no armário e ninguém confere a versão"Grave e leia uma vez na frente da turma. É o registro do ano, e registro que ninguém lê é o mesmo que registro que não existe."

Desafio extra

Faça o inventário do seu próprio kit de bancada, com seis itens e a situação real de cada um: funciona, funciona com reserva, ou não funciona. Some o que está de reserva e escreva o que você precisaria comprar para ter uma placa que não falha. Depois escreva as melhorias para o próximo ano do seu ponto de vista, com prioridade e motivo — a mesma lista que o professor leva para a coordenação, mas com a sua assinatura. Meça quanto tempo as duas listas levaram, e escreva uma frase sobre o que impede uma pessoa de fazer esse inventário com honestidade: pressa, apego à ferramenta que funciona, ou medo de descobrir que o que ela usa é o que quebrou.

>

A resolucao, compilada

// Aula 2 do dia 15: encerramento do ano e o passo depois.
//
// Ultima aula do ano. Nao ha codigo novo para aprender e nao ha prova: ha
// um ciclo fechando e duas perguntas que so o titular pode responder.
//
// A placa faz o fechamento contábil do ano. Ela conta o que o ciclo entregou
// (as 30 aulas, os 15 dias, as 3 trilhas), e ela recolhe o que faltou — o
// inventário de material, que e a parte que o professor leva para a
// coordinate e que costuma ser ignorada.
//
// Os dois blocos que o professor precisa ler em voz alta:
//
//   1. O QUE FECHOU: o ciclo que fecha, o que a turma entregou, e o numero
//      que responde "valeu a pena".
//   2. O QUE FALTOU: o material que quebrou, o que faltou comprar, e as
//      tres sugestoes de mudanca que mudam o ano que vem.
//
// A segunda lista e a que o professor vai agradecer. E a unica aula do ano
// em que o aluno escreve no codigo, e a escrita e sobre a escola, nao sobre
// o firmware.

#include <Arduino.h>

// Versao do firmware. Ultima gravacao do ano: e o que fica na placa quando
// a turma toda apagada e o laboratorio fecha.
#define VERSAO_FIRMWARE "2.0.0"

#define ID_DISPOSITIVO "esp32-bancada-01"

// ------------------------------------------------------------------ pinos

const int PIN_LED_STATUS = 2;
const int PIN_BOTAO_FECHAMENTO = 0;

// -------------------------------------------------------------- configuracao

// Numero de aulas do ano. Soma dos tres trimestres do eixo: 13 + 16 + 15
// dias, com 2 aulas por dia. O numero e medido no eixo, nao escolhido.
const int DIAS_DO_ANO = 44;
const int TOTAL_DE_AULAS_DO_ANO = 88;
const int TRIMESTRES = 3;

// Custo do material, em reais. Valor de referencia do kit da bancada, e o
// que o professor usa para calcular quanto custa matricular um aluno novo.
const float CUSTO_DO_KIT_POR_ALUNO = 145.00;

// ------------------------------------------------------------------ tipos

struct OQueFechou {
  const char* item;
  const char* como;
  bool entregue;
};

struct Material {
  const char* item;
  const char* situacao;
  int quantidade;
  bool precisaComprar;
};

struct Sugestao {
  const char* mudanca;
  const char* porque;
  int prioridade;
};

// --------------------------------------------------------------- montagem

OQueFechou fechamento[7];
int totalDoFechamento = 0;

Material materiais[6];
int totalDeMateriais = 0;

Sugestao sugestoes[4];
int totalDeSugestoes = 0;

void montarFechamento() {
  fechamento[0].item = "a camada de hardware";
  fechamento[0].como = "sensor, display e saida digital, com fiaçao certa";
  fechamento[0].entregue = true;

  fechamento[1].item = "a camada de firmware";
  fechamento[1].como = "C++ que compila, com tempo limite e log";
  fechamento[1].entregue = true;

  fechamento[2].item = "a camada de rede";
  fechamento[2].como = "WiFi que reconecta, HTTP com codigo de status";
  fechamento[2].entregue = true;

  fechamento[3].item = "a camada de servidor";
  fechamento[3].como = "Node com login, sessao, permissao e log com id";
  fechamento[3].entregue = true;

  fechamento[4].item = "a camada de banco";
  fechamento[4].como = "MySQL com repository, migracao e paginacao";
  fechamento[4].entregue = true;

  fechamento[5].item = "a camada de entrega";
  fechamento[5].como = "teste, seguranca, deploy e README que roda";
  fechamento[5].entregue = true;

  fechamento[6].item = "o projeto final";
  fechamento[6].como = "sistema completo, apresentado e revisado";
  fechamento[6].entregue = true;

  totalDoFechamento = 7;
}

void montarMateriais() {
  materiais[0].item = "ESP32 DevKit V1";
  materiais[0].situacao = "funcionando, 2 com o cabo frouxo";
  materiais[0].quantidade = 12;
  materiais[0].precisaComprar = true;

  materiais[1].item = "cabo USB";
  materiais[1].situacao = "funcionando, 1 na troca";
  materiais[1].quantidade = 12;
  materiais[1].precisaComprar = true;

  materiais[2].item = "DHT11";
  materiais[2].situacao = "2 falhando, leitura travada em 0";
  materiais[2].quantidade = 12;
  materiais[2].precisaComprar = true;

  materiais[3].item = "display OLED I2C";
  materiais[3].situacao = "funcionando, 1 com cabo solto no VCC";
  materiais[3].quantidade = 12;
  materiais[3].precisaComprar = false;

  materiais[4].item = "jumpers";
  materiais[4].situacao = "faltaram 3 kits, repuser do armario";
  materiais[4].quantidade = 12;
  materiais[4].precisaComprar = true;

  materiais[5].item = "fonte de bancada";
  materiais[5].situacao = "1 queimou em marco, falta reposicao";
  materiais[5].quantidade = 1;
  materiais[5].precisaComprar = true;

  totalDeMateriais = 6;
}

void montarSugestoes() {
  sugestoes[0].mudanca = "aumentar a aula de migracao para duas";
  sugestoes[0].porque = "a turma mais travou em migration, nao em sintaxe";
  sugestoes[0].prioridade = 1;

  sugestoes[1].mudanca = "comprar um kit de reserva antes de comprar sensor";
  sugestoes[1].porque = "placa que quebra para a aula inteira, sensor e 20 reais";
  sugestoes[1].prioridade = 1;

  sugestoes[2].mudanca = "guardar os 3 kits de jumper no armario com etiqueta";
  sugestoes[2].porque = "faltou material 3 vezes no mesmo trimestre";
  sugestoes[2].prioridade = 2;

  sugestoes[3].mudanca = "comecar o segundo trimestre com revisao de 1 aula";
  sugestoes[3].porque = "quem entrou depois da semana 2 nao acompanhou a camada de rede";
  sugestoes[3].prioridade = 2;

  totalDeSugestoes = 4;
}

// ------------------------------------------------------------------ saida

void imprimirContagem() {
  Serial.println("========================================");
  Serial.println(" o ano em numeros");
  Serial.println("========================================");
  Serial.println("trimestres:     " + String(TRIMESTRES) + " (13 + 16 + 15 dias)");
  Serial.println("aulas:          " + String(TOTAL_DE_AULAS_DO_ANO) + " (" +
                 String(DIAS_DO_ANO) + " dias de 2)");
  Serial.println("firmware:       versao " + String(VERSAO_FIRMWARE));
  Serial.println("cpu:            " + String(getCpuFrequencyMhz()) + " MHz");
  Serial.println("heap:           " + String(ESP.getFreeHeap()) + " bytes");
  Serial.println();
}

void imprimirOQueFechou() {
  Serial.println("========================================");
  Serial.println(" 1. o que este ciclo entregou");
  Serial.println("========================================");
  int entregues = 0;
  for (int i = 0; i < totalDoFechamento; i++) {
    if (fechamento[i].entregue) entregues++;
    Serial.println("  [" + String(fechamento[i].entregue ? "x" : " ") + "] " +
                   String(fechamento[i].item) + " — " + String(fechamento[i].como));
  }
  Serial.println();
  Serial.println("entregues: " + String(entregues) + " de " + String(totalDoFechamento));
  Serial.println();
  Serial.println("a camada que oano juntou e a que responde a pergunta 'onde");
  Serial.println("o dado comeca e onde ele termina'. Um aluno que sabe dizer");
  Serial.println("isso sem olhar para o diagrama fez o ano.");
  Serial.println();
}

void imprimirCusto() {
  Serial.println("========================================");
  Serial.println(" quanto custa uma vaga aberta");
  Serial.println("========================================");
  Serial.println("kit por aluno:   R$ " + String(CUSTO_DO_KIT_POR_ALUNO, 2));
  Serial.println("turma de 12:     R$ " + String(CUSTO_DO_KIT_POR_ALUNO * 12, 2));
  Serial.println("a comprar de novo:");
  int paraComprar = 0;
  for (int i = 0; i < totalDeMateriais; i++) {
    if (materiais[i].precisaComprar) paraComprar++;
  }
  Serial.println("  itens:         " + String(paraComprar) + " de " + String(totalDeMateriais));
  Serial.println();
  Serial.println("a conta que o titular faz nao e o custo do material: e o");
  Serial.println("custo de uma placa que quebrou na semana 3 e o que a aula");
  Serial.println("nao virou naquele dia. Por isso a reserva vem primeiro.");
  Serial.println();
}

void imprimirInventario() {
  Serial.println("========================================");
  Serial.println(" 2. o material: o que quebrou, o que faltou");
  Serial.println("========================================");
  for (int i = 0; i < totalDeMateriais; i++) {
    Serial.println();
    Serial.println("  " + String(materiais[i].item) + " (x" +
                   String(materiais[i].quantidade) + ")");
    Serial.println("    situacao: " + String(materiais[i].situacao));
    Serial.println("    comprar: " + String(materiais[i].precisaComprar ? "SIM" : "nao"));
  }
  Serial.println();
  Serial.println("esta e a lista que o professor leva para a coordenacao.");
  Serial.println("ela nao vai para o portal do aluno: sao problemas internos");
  Serial.println("da escola, e o aluno nao tem o que fazer com isso.");
  Serial.println();
}

void imprimirSugestoes() {
  Serial.println("========================================");
  Serial.println(" as sugestoes para o proximo ano");
  Serial.println("========================================");
  for (int i = 0; i < totalDeSugestoes; i++) {
    Serial.println();
    Serial.println("  prioridade " + String(sugestoes[i].prioridade) + ": " +
                   String(sugestoes[i].mudanca));
    Serial.println("    porque: " + String(sugestoes[i].porque));
  }
  Serial.println();
  Serial.println("prioridade 1 e o que muda o ano; prioridade 2 e o que so");
  Serial.println("tira trabalho. A ordem importa: comprar jumper antes de");
  Serial.println("mudar o conteudo e o que o aluno sente na aula.");
  Serial.println();
}

void imprimirEncerramento() {
  Serial.println("========================================");
  Serial.println(" 3. encerramento");
  Serial.println("========================================");
  Serial.println("o ciclo fecha aqui, e a placa fica na bancada com a ultima");
  Serial.println("gravacao. A proxima turma recebe o mesmo kit e o mesmo");
  Serial.println("material, so que com as correcoes desta lista aplicadas.");
  Serial.println();
  Serial.println("obrigado: a placa imprime uma vez por boot, e o professor");
  Serial.println("nao precisa ler a palavra para dizer a de verdade.");
  Serial.println();
  Serial.println("a proxima etapa e continuar estudando, com projeto proprio");
  Serial.println("e com a sequencia de ports: firmware, depois servidor, depois");
  Serial.println("os dois juntos. O ano que vem comeca onde este terminou.");
  Serial.println();
}

// ---------------------------------------------------------------- setup

void setup() {
  Serial.begin(115200);
  delay(400);

  pinMode(PIN_LED_STATUS, OUTPUT);
  pinMode(PIN_BOTAO_FECHAMENTO, INPUT_PULLUP);
  digitalWrite(PIN_LED_STATUS, HIGH);

  Serial.println();
  Serial.println("========================================");
  Serial.println("========================================");
  Serial.println(" FIM DO ANO LETIVO — v" + String(VERSAO_FIRMWARE));
  Serial.println("========================================");
  Serial.println("========================================");
  Serial.println("dispositivo: " + String(ID_DISPOSITIVO) + " | ultima gravacao do ano");
  Serial.println();

  montarFechamento();
  montarMateriais();
  montarSugestoes();

  imprimirContagem();
  imprimirOQueFechou();
  imprimirCusto();
  imprimirInventario();
  imprimirSugestoes();
  imprimirEncerramento();

  Serial.println("========================================");
  Serial.println(" placa de encerramento ligada e respondendo");
  Serial.println("========================================");
}

void loop() {
  // A placa fica viva ate o fim do periodo letivo. Nao e preciso manter
  // isso ligado, e o que importa e o registro: a ultima versao gravada
  // e a que fica no historico do laboratorio.
  digitalWrite(PIN_LED_STATUS, !digitalRead(PIN_LED_STATUS));

  if (digitalRead(PIN_BOTAO_FECHAMENTO) == LOW) {
    static unsigned long ultimoToque = 0;
    if (millis() - ultimoToque > 2000) {
      ultimoToque = millis();
      Serial.println();
      Serial.println("========================================");
      Serial.println(" ate a proxima");
      Serial.println("========================================");
      Serial.println("dispositivo: " + String(ID_DISPOSITIVO) + " v" + String(VERSAO_FIRMWARE));
      Serial.println("firmware gravado em: " + String(__DATE__) + " as " + String(__TIME__));
      Serial.println("heap: " + String(ESP.getFreeHeap()) + " bytes | cpu: " +
                     String(getCpuFrequencyMhz()) + " MHz");
      Serial.println("========================================");
      Serial.println();
    }
  }

  Serial.println("[fim do ano] viva | v" + String(VERSAO_FIRMWARE) + " | heap " +
                 String(ESP.getFreeHeap()) + " B | LED " +
                 String(digitalRead(PIN_LED_STATUS) ? "aceso" : "apago"));
  delay(9000);
}

Sem saída de compilação gravada. Rode python3 validar.py -t 3 dia15 aula2.