feat(sono): madrugada silenciosa e N sons para acordar

Antes um único som acima do limiar, um quadro de movimento ou um pulso
do PIR acordavam o rosto; deitado na cama, ele acordava toda hora.

- Som: precisa de `somAcordar` barulhos (padrão 3) em 1 minuto; o mesmo
  barulho comprido conta uma vez.
- Madrugada silenciosa (padrão 23h às 7h, configurável): movimento,
  rastreamento, PIR e modo presença não acordam; só barulho ALTO
  repetido, toque ou conversa.
- Vida: de madrugada não acorda sozinho e volta a dormir mesmo com gente
  se mexendo, a não ser que alguém tenha interagido nos últimos 10 min.
- Painel: grupo "Sono e madrugada" nos Ajustes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
julio
2026-10-06 04:48:11 -03:00
co-authored by Claude Opus 5.5
parent 5fcd038861
commit dd40c730be
8 changed files with 135 additions and 22 deletions
+7 -4
View File
@@ -32,7 +32,7 @@ from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import unquote
from pathlib import Path
from comum import autorizado, carregar_token, gravar_atomico, ler_json
from controle_pc import ControlePC, versao
from controle_pc import ControlePC, madrugada, versao
from eventos import Eventos
from servos import ControleServos
from braco import Braco
@@ -505,13 +505,15 @@ def main():
vida.celular_dormindo = celular_dormindo
vida.celular_online = lambda: servidor.controle.resumo()['online']
vida.alguem_perto = alguem_perto
vida.madrugada = lambda agora: madrugada(servidor.controle.config, agora)
# E-Stop parado, ou modo presença com ninguém em casa (dormindo em silêncio): não faz nada
vida.bloqueado = lambda: ESTOP["ativo"] or servidor.historico.presenca.get("estado") == "ausente"
def presenca(tipo):
vida.estimulo(tipo)
# PIR viu alguém: se o rosto estiver dormindo (e talvez com a tela apagada), acorda
if tipo == "pir":
# PIR viu alguém: se o rosto estiver dormindo (e talvez com a tela apagada), acorda.
# De madrugada não: alguém se mexendo na cama não é motivo para acordar.
if tipo == "pir" and not madrugada(servidor.controle.config):
with servidor.controle.lock:
dormindo = bool(servidor.controle.estado.get("dormindo"))
if dormindo:
@@ -523,7 +525,8 @@ def main():
def alguem_chegou():
camera(True) # modo presença: o PIR liga a câmera do celular
enfileirar("acordar")
if not madrugada(servidor.controle.config):
enfileirar("acordar")
def ninguem_por_perto():
camera(False) # sem ninguém: câmera desligada, dorme e fica em silêncio