feat(ao-vivo): indicador ao vivo do sensor PIR
Cada disparo do PIR vira um evento SSE 'pir' (mesmo dentro do intervalo do historico) e o painel mostra 'presenca agora' por 8 s em Ao vivo e no Historico; /estado inclui o estado do PIR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,8 @@ class Estado {
|
||||
treinamento = $state({ ocupado: false, erro: '' });
|
||||
api = $state<EstadoServidor['api'] | null>(null);
|
||||
feed = $state<ItemFeed[]>([]);
|
||||
/** Sensor PIR da placa: último disparo (s, epoch) e se está ligado. */
|
||||
pir = $state<{ disponivel: boolean; ultimo: number | null } | null>(null);
|
||||
/** Relógio de 1 s para derivar "online" sem esperar evento novo. */
|
||||
agora = $state(Date.now());
|
||||
|
||||
@@ -106,6 +108,7 @@ function aplicarFoto(f: EstadoServidor) {
|
||||
estado.reacao = f.reacao ?? null;
|
||||
if (f.treinamento) estado.treinamento = f.treinamento;
|
||||
if (f.api) estado.api = f.api;
|
||||
if (f.pir) estado.pir = { disponivel: f.pir.disponivel, ultimo: f.pir.ultimo };
|
||||
}
|
||||
|
||||
const tratadores: Record<string, (d: any) => void> = {
|
||||
@@ -139,6 +142,7 @@ const tratadores: Record<string, (d: any) => void> = {
|
||||
if (d?.receita?.nome) noFeed('reacao', 'Reação: ' + d.receita.nome);
|
||||
},
|
||||
treinamento: (d) => (estado.treinamento = d),
|
||||
pir: (d: { ultimo: number }) => (estado.pir = { disponivel: true, ultimo: d.ultimo }),
|
||||
historico: (d) => {
|
||||
const n = d?.novo;
|
||||
if (n) noFeed('historico', { pir: '🚶 Presença no PIR', movimento: '👀 Movimento na câmera', som: '🔊 Som alto' }[n.tipo as string] ?? 'Detecção');
|
||||
@@ -165,7 +169,7 @@ function abrirEventos() {
|
||||
if (estado.conexao !== 'token') estado.conexao = 'caiu';
|
||||
};
|
||||
for (const tipo of ['expressao', 'telemetria', 'app_config', 'aparencia', 'motores', 'estop', 'conversa', 'ia',
|
||||
'reacao', 'treinamento', 'historico']) {
|
||||
'reacao', 'treinamento', 'historico', 'pir']) {
|
||||
fonte.addEventListener(tipo, (e) => {
|
||||
const dados = JSON.parse((e as MessageEvent).data);
|
||||
tratadores[tipo]?.(dados);
|
||||
|
||||
Reference in New Issue
Block a user