Audiência: Este artigo destina-se a responsáveis pela privacidade, arquitetos de TI de agrupamentos de escolas e ministérios, parceiros OEM que integram dashboards de saúde de frotas e importadores B2B que precisam de responder à pergunta «o que é que a caneta reporta de volta para a fábrica?» para compradores na UE, nos EUA, no Golfo e na América Latina. Partimos do princípio de que compreende o GDPR e a COPPA a nível conceptual, mas pretende saber exatamente que classes de eventos saem das canetas B1/B2/F8/K7/KF1/L5/P2/Q6/Q8/T2/Y6, quais são anonimizadas, quais são opt-in e quais nunca são transmitidas.
Uma cooperativa escolar espanhola que adquiriu 12 000 canetas colocou à nossa equipa de conformidade uma pergunta muito concreta no último trimestre: «Ao abrigo do Artigo 25.º do GDPR, que dados saem do dispositivo, que dados permanecem no dispositivo, e pode um encarregado de educação exercer o direito de oposição sem perder a cobertura da garantia?» A resposta honesta teria 23 páginas. A resposta curta, que publicamos aqui, é que os eventos de telemetria são opt-out por predefinição na UE, opt-in por predefinição nos EUA ao abrigo da COPPA, opt-in por predefinição na Arábia Saudita ao abrigo da SFDA, e nunca ativos por predefinição em frotas OEM auto-hospedadas. Abaixo apresentamos a engenharia por detrás dessas políticas.
Este artigo abrange o buffer circular de registos no dispositivo, o esquema de eventos, o pipeline de anonimização, o calendário de carregamento, a postura GDPR/COPPA/PIPL/LGPD, as métricas de saúde da frota expostas pelo dashboard e o custo de operar a telemetria em mais de 47 000 canetas distribuídas por 47 países.
1. O Buffer Circular de Registos no Dispositivo
Todas as canetas dispõem de um buffer circular de 512 KB na partição de dados do utilizador. O buffer é apenas de anexação, indexado pelo tempo e sobrevive a uma reposição de fábrica apenas se o encarregado de educação selecionar «preservar registos de diagnóstico» — opção que é a predefinição em implementações enterprise e está desativada por predefinição na venda a retalho.
1.1 Parâmetros do Buffer por Modelo
| Modelo | Partição | Tamanho do buffer | Registos de eventos | Retenção (dias) |
|---|---|---|---|---|
| B1 | NOR de dados do utilizador | 256 KB | 2 800 | 14 |
| B2 | NOR de dados do utilizador | 256 KB | 2 800 | 14 |
| F8 | NAND de dados do utilizador | 512 KB | 5 600 | 21 |
| K7 / KF1 | NAND de dados do utilizador | 512 KB | 5 600 | 21 |
| L5 | NAND de dados do utilizador | 1 MB | 11 200 | 30 |
| P2 | NOR de dados do utilizador | 256 KB | 2 800 | 14 |
| Q6 / Q8 | NAND de dados do utilizador | 1 MB | 11 200 | 30 |
| T2 / Y6 | NAND de dados do utilizador | 2 MB | 22 400 | 45 |
O buffer está dimensionado para conter a classe de eventos de maior volume (app.evt) durante 14 a 45 dias, consoante o modelo. O buffer é cíclico: os eventos mais antigos são os primeiros a ser descartados.
1.2 Esquema de Eventos
Cada registo é uma estrutura fixa de 96 bytes com 1 byte de tipo, 4 bytes de carimbo temporal, 2 bytes de versão do esquema e 89 bytes de payload específico do tipo.
struct telemetry_event_t {
uint8_t type; // 0x01..0x2C
uint32_t timestamp; // segundos desde o arranque
uint16_t schema_ver; // p. ex., 0x0007
uint8_t severity; // 0..3 (info, aviso, erro, crítico)
uint8_t reserved;
uint8_t payload[80];
uint16_t crc; // CRC-16-CCITT
uint8_t sig_pad[6]; // reservado para assinatura curta Ed25519
} __attribute__((packed));
O payload é específico do tipo. Um evento boot.end transporta um uint32 com a duração do arranque; um evento oid.lookup transporta um uint16 com a latência e um uint16 com o bucket da página de dicionário; um evento app.crash transporta um hash de impressão digital de stack de 64 bytes.
2. Classes de Eventos
Definimos 44 classes de eventos. Nem todas são carregadas. A classificação é LOCAL (nunca carregado), TELEMETRY (carregado, anonimizado), ou SUPPORT (carregado apenas com consentimento explícito do utilizador).
| Classe | Contagem | Postura predefinida | Exemplo |
|---|---|---|---|
| Apenas local | 18 | LOCAL | key.press, book.open, app.locale |
| Telemetria (anonimizada) | 19 | TELEMETRY | boot.end, oid.lookup, pwr.drain, fw.update |
| Suporte (opt-in) | 7 | SUPORTE | voice.clip, asr.utterance, dict.override |
Os 18 eventos LOCAIS permanecem no dispositivo e são utilizados apenas para funcionalidades na aplicação, como "retomar onde ficou." Os 19 eventos de TELEMETRIA são enviados em lotes através de Wi-Fi. Os 7 eventos de SUPORTE são enviados apenas quando o progenitor ou administrador da frota ativa explicitamente o modo de suporte.
3. Regras de Anonimização
Cada evento de TELEMETRIA passa por um pipeline de anonimização em 4 fases antes do envio. O pipeline é executado no dispositivo e é reforçado pelo bootloader; mesmo uma aplicação comprometida não o pode contornar.
- Remover identificadores — O número de série do dispositivo é substituído por um salt rotativo por arranque. O salt é um valor aleatório de 128 bits regenerado a cada cold boot.
- Agrupar valores — As latências são arredondadas para os 10 ms mais próximos. Os níveis de bateria são arredondados para os 5% mais próximos. As consultas ao dicionário são agrupadas em níveis CEFR.
- Calcular hash de impressões digitais — As stack traces são transformadas em hash com um salt por frota. O salt é rodado mensalmente e nunca é enviado.
- Agregar na origem — Eventos individuais são agregados em janelas de 15 minutos no dispositivo. O dispositivo envia um registo por janela, não 30 eventos individuais.
O registo agregado contém: timestamp da janela, ID da frota (um hash de 32 bits da subchave OEM), modelo, versão de firmware, código de região e 6 contadores de métricas. Não contém o número de série do dispositivo, o nome do progenitor, o nome da criança nem qualquer conteúdo que a criança tenha tocado.
4. Calendário e Agregação de Envios
Os envios ocorrem apenas através de Wi-Fi, nunca via rede móvel (não incluímos modem celular). O calendário padrão é:
| Condição | Comportamento |
|---|---|
| Wi-Fi associado, inativo >5 min | Enviar lote pendente |
| Bateria <20% | Adiar envio |
| Bateria <10% | Cancelar carregamento, manter lote localmente |
| Carregador ligado, qualquer bateria | Carregar imediatamente |
| Administrador da frota força o carregamento | Carregar agora, independentemente do estado |
Uma caneta típica carrega 1–3 registos em lote por dia, totalizando 18–54 KB. Numa frota de 12 000 canetas ao longo de uma semana escolar, o volume de carregamento é de 1,6–4,8 GB por semana, o que se enquadra confortavelmente numa única linha de banda larga empresarial.
5. Postura GDPR / COPPA / PIPL / LGPD
O comportamento de telemetria predefinido varia consoante a jurisdição. A fábrica define o valor predefinido com base nas regulamentações do destino de envio.
| Jurisdição | Telemetria predefinida | Suporte predefinido | Mecanismo de exclusão |
|---|---|---|---|
| UE (RGPD) | OPT-OUT | OFF | Definições → Privacidade → Telemetria |
| RU (RGPD + DPA) | OPT-OUT | OFF | Definições → Privacidade → Telemetria |
| EUA (COPPA, menores de 13 anos) | OPT-IN | OFF | Assistente de primeira inicialização |
| EUA (13+ anos, leis estatais) | OPT-OUT | OFF | Definições → Privacidade → Telemetria |
| Arábia Saudita (SFDA, PTA) | OPT-IN | OFF | Assistente de primeira inicialização + portal PTA |
| EAU (TDRA) | OPT-IN | OFF | Assistente de primeira inicialização + portal TDRA |
| China (PIPL) | OPT-IN | OFF | Assistente de primeira inicialização + consentimento PIPL |
| Brasil (LGPD) | OPT-OUT | OFF | Definições → Privacidade → Telemetria |
| México (LFPDPPP) | OPT-OUT | OFF | Definições → Privacidade → Telemetria |
| Todas as outras regiões | OPT-OUT | OFF | Definições → Privacidade → Telemetria |
Em todas as jurisdições, o progenitor ou administrador da frota pode desativar a telemetria sem perder a cobertura da garantia, sem perder o acesso às atualizações OTA e sem perder o acesso ao suporte. A única funcionalidade desativada ao recusar é o dashboard de saúde da frota, que requer telemetria agregada para funcionar.
6. Dashboard de Métricas de Saúde da Frota
Para parceiros OEM e operadores de frotas de grande dimensão, o dashboard de telemetria expõe 9 métricas ao nível da frota. Nenhuma métrica pode ser detalhada até um único número de série de dispositivo.
| Métrica | Definição | Utilização |
|---|---|---|
| Taxa de atividade diária | (canetas com ≥1 arranque em 24 h) / (dimensão da frota) | Engajamento |
| Sessões sem falhas | (sessões sem exceção não tratada) / (sessões) | Estabilidade |
| OID lookup p95 | Percentil 95 de OID-para-pronúncia | Desempenho |
| Saúde da bateria | Canetas a reportar <80% da capacidade original | Ciclo de vida do hardware |
| Taxa de adoção de OTA | (canetas com firmware mais recente) / (dimensão da frota) | Velocidade de atualização |
| Taxa de acerto do dicionário | (pesquisas servidas a partir da cache) / (pesquisas) | Desempenho |
| Sucesso no carregamento de pacotes de idiomas | (carregamentos de LP sem falha de assinatura) / (carregamentos) | Integridade do conteúdo |
| Taxa de eventos de carregamento | (sessões de carregamento por caneta por semana) | Padrão de utilização |
| Mistura de gravidade de erros | Distribuição de eventos de gravidade 0–3 | Saúde |
O dashboard é gratuito para frotas acima de 5.000 canetas. Abaixo disso, o custo é de $0,04 por caneta por ano, com faturação mensal.
7. Visualização SVG do pipeline de telemetria e da combinação de métricas
8. Custos
| Serviço | Custo | Notas |
|---|---|---|
| Dashboard de telemetria alojado (5.000+ canetas) | incluído no portal OEM | Gratuito |
| Dashboard de telemetria alojado (<5.000 canetas) | $0,04/caneta/ano | Faturado mensalmente |
| Sink de telemetria auto-hospedado | $1.800/ano | Por distribuidor |
| Classe de evento personalizada (por tipo) | $2.400 pagamento único + $0,06/caneta/ano | Por parceiro OEM |
| Apoio na avaliação de impacto na privacidade | $1.200 | Por região |
| Certificado de eliminação de dados (RGPD Art. 17.º) | $0 | Self-service via portal |
Conselho ao comprador: Para implementações na UE acima de 10.000 canetas, solicite uma amostra do certificado de eliminação de dados através do portal antes de assinar a PO. O certificado é um PDF de 1 página com o timestamp de eliminação e o SHA-256 do conjunto de registos apagados.
8. Anexo: Exemplo prático de anonimização e inventário de classes de eventos
8.1 Um exemplo prático de anonimização
Considere a sequência de eventos brutos abaixo, capturada numa Q8 real numa implementação escolar na Arábia Saudita. Vamos acompanhar cada etapa do pipeline de anonimização em 4 fases.
Eventos brutos oid.lookup capturados no dispositivo (janela de amostra, 14:00–14:15 local):
14:02:11 oid.lookup serial=QC8-24-118-00472 lat=98ms page=412 word="الفيل"
14:03:48 oid.lookup serial=QC8-24-118-00472 lat=104ms page=412 word="يمشي"
14:05:22 oid.lookup serial=QC8-24-118-00472 lat=88ms page=412 word="ببطء"
14:09:17 oid.lookup serial=QC8-24-118-00472 lat=101ms page=412 word="في"
14:11:46 oid.lookup serial=QC8-24-118-00472 lat=94ms page=412 word="الحديقة"
Fase 1 — remoção de identificadores. O número de série é substituído por um salt rotativo de 128 bits por arranque e, em seguida, hash para um ID de bucket de 32 bits. O ID de bucket 0x4A12F8E1 não pode ser revertida para o número de série sem o salt, e o salt é apagado no próximo arranque a frio.
Etapa 2 — agrupar em intervalos. As latências são arredondadas aos 10 ms mais próximos. A página é agrupada em CEFR A1 (páginas 1–500), A2 (páginas 501–1,200), B1 (páginas 1,201–2,000).
Etapa 3 — impressões digitais por hash. Sem stack traces nesta janela.
Etapa 4 — agregar na origem. Os 5 eventos são consolidados num único registo.
Resultado: um registo carregado às 14:15:
{
"fleet_id": "0x4A12F8E1",
"model": "Q8",
"fw": "3.3.1",
"region": "SA",
"window": "2026-09-12T14:15:00Z",
"events": {
"oid_lookup_count": 5,
"oid_lookup_p95_ms": 100,
"cefr_bucket": "A2",
}
}
É isto que o dashboard da frota vê. Não há caminho de regresso à criança, ao encarregado de educação ou à caneta específica — o ID do intervalo roda a cada arranque.
8.2 Inventário Completo de Classes de Eventos (n=44)
A taxonomia completa de eventos, agrupada por subsistema e postura predefinida:
| ID | Evento | Postura | Janela de agregação | Notas |
|---|---|---|---|---|
| 0x01 | boot.start | TELEMETRY | 15 min | Conta arranques a frio |
| 0x02 | boot.end | TELEMETRY | 15 min | Duração do arranque a frio |
| 0x03 | pwr.drain | TELEMETRY | 15 min | Taxa de descarga da bateria |
| 0x04 | pwr.charge | TELEMETRIA | 15 min | Pico de corrente de carga |
| 0x05 | key.press | LOCAL | n/a | Mapa de botões |
| 0x06 | book.open | LOCAL | n/a | Posição de retomada |
| 0x07 | book.close | LOCAL | n/a | Posição de retomada |
| 0x08 | oid.lookup | TELEMETRIA | 15 min | Latência em intervalos |
| 0x09 | oid.miss | TELEMETRIA | 15 min | Código não está em nenhum livro carregado |
| 0x0A | dict.hit | TELEMETRIA | 15 min | Taxa de acerto da cache |
| 0x0B | dict.miss | TELEMETRIA | 15 min | Latência de consulta a frio |
| 0x0C | lp.load | TELEMETRIA | 15 min | Verificação de assinatura LP |
| 0x0D | tts.speak | TELEMETRIA | 15 min | Latência do primeiro byte |
| 0x0E | asr.utterance | SUPORTE | por sessão | Apenas com consentimento |
| 0x0F | asr.result | SUPORTE | por sessão | Apenas com consentimento |
| 0x10 | app.crash | TELEMETRIA | 15 min | Hash da stack |
| 0x11 | app.err | TELEMETRIA | 15 min | Gravidade 0–3 |
| 0x12 | fw.update | TELEMETRIA | por versão | Staging OTA |
| 0x13 | fw.rollback | TELEMETRIA | por versão | Contagem de reversões |
| 0x14 | dict.update | TELEMETRIA | por versão | OTA do dicionário |
| 0x15 | lp.update | TELEMETRIA | por versão | OTA do LP |
| 0x16 | wifi.assoc | TELEMETRY | 15 min | Tempo de autenticação |
| 0x17 | wifi.fail | TELEMETRY | 15 min | Falha de autenticação |
| 0x18 | ble.pair | TELEMETRY | 15 min | Confirmação SSP |
| 0x19 | ble.fail | TELEMETRY | 15 min | Falha de emparelhamento |
| 0x1A | nfc.read | LOCAL | n/a | Apenas UID da tag |
| 0x1B | usbc.plug | LOCAL | n/a | Contagem de inserções USB-C |
| 0x1C | usbc.pd | TELEMETRY | 15 min | PDO aceite |
| 0x1D | batt.health | TELEMETRY | diária | Degradação da capacidade |
| 0x1E | therm.warn | TELEMETRY | 15 min | Térmico do PMIC |
| 0x1F | wear.delta | TELEMETRY | diária | Contador de desgaste da flash |
| 0x20 | err.s0 | TELEMETRY | por evento | Acionador de paragem global |
| 0x21 | err.s1 | TELEMETRY | 15 min | Contagem S1 |
| 0x22 | err.s2 | TELEMETRY | 15 min | Contagem S2 |
| 0x23 | err.s3 | TELEMETRY | 15 min | Contagem S3 |
| 0x24 | app.locale | LOCAL | n/a | Idioma da interface |
| 0x25 | app.theme | LOCAL | n/a | Tema da interface |
| 0x26 | voice.clip | SUPORTE | por sessão | Apenas opt-in |
| 0x27 | voice.share | SUPORTE | por sessão | Apenas opt-in |
| 0x28 | voice.delete | SUPORTE | por sessão | Apenas com consentimento |
| 0x29 | dict.override | SUPORTE | por sessão | Apenas com consentimento |
| 0x2A | parent.pin | LOCAL | n/d | Controlo parental |
| 0x2B | screen.time | LOCAL | n/d | Duração diária da sessão |
| 0x2C | session.end | TELEMETRIA | 15 min | Duração da sessão |
Dos 44 eventos, 18 são LOCAL, 19 são TELEMETRIA e 7 são SUPORTE. O inventário completo está publicado no portal OEM no modelo de avaliação de impacto sobre a privacidade.
10. Visual: Distribuição das Classes de Eventos e Orçamento de Largura de Banda
A visualização abaixo combina um gráfico de setores com as três classes de eventos (LOCAL/TELEMETRIA/SUPORTE) e uma coluna com o orçamento mensal de largura de banda por caneta. O valor de 152 KB é o número contratual público que partilhamos com os serviços de compras das escolas.
Leitura Relacionada
- GDPR e Proteção de Dados UE para Canetas de Leitura
- Caneta de leitura COPPA e controlo parental
- Arquitetura IoT na nuvem da caneta de leitura com MQTT
- Mecanismo de atualização OTA do firmware da caneta de leitura
- Encriptação de dados da caneta de leitura AES-128 vs AES-256
- Programas OEM de canetas de leitura