feat(presenca): sensibilidade do PIR por confirmação (padrão média)

O HC-SR505 não tem ajuste físico e disparava por pouco (57 disparos numa
hora de madrugada). Agora só conta como presença o disparo confirmado:
média = 2 em 1 min ou ligado direto 12 s; baixa = 3 em 90 s ou 20 s;
alta = qualquer um. A bolinha do Ao vivo segue o pino cru. Ajuste em
Eventos › Modo presença.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
julio
2026-10-10 19:05:20 -03:00
co-authored by Claude Opus 5.5
parent 6e80332a8d
commit 7b0a05435f
5 changed files with 126 additions and 8 deletions
+33
View File
@@ -97,6 +97,7 @@ class HistoricoTest(unittest.TestCase):
avisos = []
self.h.publicar = lambda tipo, dados: avisos.append((tipo, dados))
self.h.pir['disponivel'] = True
self.h.config['sensibilidade_pir'] = 'alta' # qualquer disparo conta
self.h.nivel_pir(True, agora=1000) # subida: evento + bolinha acesa
self.assertTrue(self.h.pir['ativo'])
self.assertEqual(self.h.status()['eventos'][0]['tipo'], 'pir')
@@ -107,6 +108,38 @@ class HistoricoTest(unittest.TestCase):
self.assertTrue(self.h.checar_ausencia(1000 + 15 * 60 + 1))
self.assertIn(('pir', True), [(t, d.get('ativo')) for t, d in avisos])
def test_sensibilidade_do_pir_confirma_antes_de_contar(self):
detectados = []
self.h.ao_detectar = detectados.append
self.h.config['intervalo'] = 0
# média (padrão): um disparo solto só acende a bolinha
self.h.nivel_pir(True, agora=1000)
self.assertTrue(self.h.pir['ativo'])
self.h.nivel_pir(False, agora=1008) # o HC-SR505 segura ~8 s
self.assertEqual((self.h.status()['total'], detectados), (0, []))
self.h.nivel_pir(True, agora=1040) # segundo disparo em menos de 1 min
self.assertEqual(detectados, ['pir'])
self.h.nivel_pir(False, agora=1048)
self.h.nivel_pir(True, agora=1200) # 2 min depois: solto de novo
self.h.nivel_pir(False, agora=1208)
self.assertEqual(len(detectados), 1)
# alguém se mexendo na frente: o sensor fica ligado direto e confirma
self.h.nivel_pir(True, agora=2000)
self.h.checar_pir(2010)
self.assertEqual(len(detectados), 1)
self.h.checar_pir(2012)
self.assertEqual(len(detectados), 2)
self.h.nivel_pir(False, agora=2030)
# baixa: precisa de 3 disparos em 90 s
self.h.config['sensibilidade_pir'] = 'baixa'
for t in (3000, 3030):
self.h.nivel_pir(True, agora=t); self.h.nivel_pir(False, agora=t + 8)
self.assertEqual(len(detectados), 2)
self.h.nivel_pir(True, agora=3060)
self.assertEqual(len(detectados), 3)
with self.assertRaises(ValueError):
Historico.validar(dict(sensibilidade_pir='maxima'))
def test_apagar_e_limpar(self):
a = self.h.registrar('pir', agora=1); self.h.guardar_foto(a, JPEG)
b = self.h.registrar('som', agora=1)