Ajuste 24 Horas

This commit is contained in:
2026-03-27 00:14:30 -03:00
parent 09a31f42e0
commit 464f9d4426

View File

@@ -1,285 +1,285 @@
import os import os
import requests import smtplib
import smtplib from datetime import datetime
from email.mime.text import MIMEText from email.mime.text import MIMEText
from datetime import datetime from pathlib import Path
import pytz
from dotenv import load_dotenv import pytz
import requests
# Carregar variáveis de ambiente from dotenv import load_dotenv
load_dotenv()
# Configurações # Carrega .env sempre pelo caminho do projeto (independente do CWD)
EVOLUTION_API_URL = os.getenv("EVOLUTION_API_URL") BASE_DIR = Path(__file__).resolve().parent
EVOLUTION_INSTANCE_ID = os.getenv("EVOLUTION_INSTANCE_ID") load_dotenv(dotenv_path=BASE_DIR / ".env")
EVOLUTION_API_TOKEN = os.getenv("EVOLUTION_API_TOKEN")
EVOLUTION_SENDER_INSTANCE = os.getenv("EVOLUTION_SENDER_INSTANCE", "Wander")
N8N_WEBHOOK_URL = os.getenv("N8N_WEBHOOK_URL") EVOLUTION_API_URL = os.getenv("EVOLUTION_API_URL")
WHATSAPP_NUMBER = os.getenv("WHATSAPP_NUMBER") EVOLUTION_INSTANCE_ID = os.getenv("EVOLUTION_INSTANCE_ID")
SMTP_SERVER = os.getenv("SMTP_SERVER", "smtp-mail.outlook.com") EVOLUTION_API_TOKEN = os.getenv("EVOLUTION_API_TOKEN")
SMTP_PORT = int(os.getenv("SMTP_PORT", 587)) EVOLUTION_SENDER_INSTANCE = os.getenv("EVOLUTION_SENDER_INSTANCE", "Wander")
SMTP_EMAIL = os.getenv("SMTP_EMAIL") N8N_WEBHOOK_URL = os.getenv("N8N_WEBHOOK_URL")
SMTP_PASSWORD = os.getenv("SMTP_PASSWORD") WHATSAPP_NUMBER = os.getenv("WHATSAPP_NUMBER")
EMAIL_TO = os.getenv("EMAIL_TO") SMTP_SERVER = os.getenv("SMTP_SERVER", "smtp-mail.outlook.com")
SMTP_PORT = int(os.getenv("SMTP_PORT", 587))
# Timezone configurável via variável de ambiente SMTP_EMAIL = os.getenv("SMTP_EMAIL")
TIMEZONE = os.getenv("TIMEZONE", "America/Sao_Paulo") SMTP_PASSWORD = os.getenv("SMTP_PASSWORD")
tz = pytz.timezone(TIMEZONE) EMAIL_TO = os.getenv("EMAIL_TO")
def get_now(): TIMEZONE = os.getenv("TIMEZONE", "America/Sao_Paulo")
"""Retorna datetime atual com timezone configurado.""" tz = pytz.timezone(TIMEZONE)
return datetime.now(tz)
def get_headers(): def _normalize_env(value):
return { if value is None:
"apikey": EVOLUTION_API_TOKEN, return None
"Authorization": f"Bearer {EVOLUTION_API_TOKEN}", cleaned = value.strip()
"Content-Type": "application/json" return cleaned if cleaned else None
}
def send_email_error(error_details): def _required_env_missing():
"""Envia email de erro caso algo falhe.""" required = {
try: "EVOLUTION_API_URL": _normalize_env(EVOLUTION_API_URL),
now = get_now() "EVOLUTION_API_TOKEN": _normalize_env(EVOLUTION_API_TOKEN),
subject = "🚨 ERRO - Monitor Evolution API" "EVOLUTION_SENDER_INSTANCE": _normalize_env(EVOLUTION_SENDER_INSTANCE),
body = f"Falha no monitoramento.\nHorário: {now.strftime('%d/%m/%Y %H:%M:%S')}\n\nDetalhes do Erro:\n{error_details}" "N8N_WEBHOOK_URL": _normalize_env(N8N_WEBHOOK_URL),
"SMTP_EMAIL": _normalize_env(SMTP_EMAIL),
msg = MIMEText(body) "SMTP_PASSWORD": _normalize_env(SMTP_PASSWORD),
msg['Subject'] = subject "EMAIL_TO": _normalize_env(EMAIL_TO),
msg['From'] = SMTP_EMAIL "WHATSAPP_NUMBER": _normalize_env(WHATSAPP_NUMBER),
msg['To'] = EMAIL_TO }
return [name for name, value in required.items() if not value]
# Ler configuração de segurança (Default: STARTTLS)
smtp_security = os.getenv("SMTP_SECURITY", "STARTTLS").upper()
def get_now():
if smtp_security == "SSL": return datetime.now(tz)
server = smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT)
else:
server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT) def get_headers():
if smtp_security == "STARTTLS": token = _normalize_env(EVOLUTION_API_TOKEN) or ""
server.starttls() return {
"apikey": token,
with server: "Authorization": f"Bearer {token}",
server.login(SMTP_EMAIL, SMTP_PASSWORD) "Content-Type": "application/json",
server.send_message(msg) }
return True, "Email de erro enviado com sucesso."
except Exception as e: def send_email_error(error_details):
return False, f"Falha ao enviar email: {str(e)}" try:
now = get_now()
def send_whatsapp_success(): subject = "ERRO - Monitor Evolution API"
"""Envia mensagem de sucesso via Evolution API.""" body = (
try: "Falha no monitoramento.\n"
url = f"{EVOLUTION_API_URL}/message/sendText/{EVOLUTION_SENDER_INSTANCE}" f"Horario: {now.strftime('%d/%m/%Y %H:%M:%S')}\n\n"
f"Detalhes do Erro:\n{error_details}"
now = get_now() )
message_text = (
f"✅ *MONITOR OK*\n\n" msg = MIMEText(body)
f"📅 Data: {now.strftime('%d/%m/%Y')}\n" msg["Subject"] = subject
f"🕐 Horário: {now.strftime('%H:%M:%S')}\n\n" msg["From"] = SMTP_EMAIL
f"• Evolution API: Online\n" msg["To"] = EMAIL_TO
f"• Webhook Instância: Habilitado\n"
f"• Webhook N8N: Funcionando\n\n" smtp_security = os.getenv("SMTP_SECURITY", "STARTTLS").upper()
f"Todos os serviços operacionais."
) if smtp_security == "SSL":
server = smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT)
payload = { else:
"number": WHATSAPP_NUMBER, server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
"text": message_text if smtp_security == "STARTTLS":
} server.starttls()
# A Evolution API às vezes aceita apikey no header ou como query param, with server:
# mas o padrão aqui é usar o header configurado. server.login(SMTP_EMAIL, SMTP_PASSWORD)
response = requests.post(url, json=payload, headers=get_headers(), timeout=10) server.send_message(msg)
if response.status_code == 200 or response.status_code == 201: return True, "Email de erro enviado com sucesso."
return True, "WhatsApp de sucesso enviado." except Exception as exc:
else: return False, f"Falha ao enviar email: {exc}"
return False, f"Falha ao enviar WhatsApp: {response.text}"
except Exception as e: def send_whatsapp_success():
return False, f"Erro na requisição WhatsApp: {str(e)}" try:
base_url = (_normalize_env(EVOLUTION_API_URL) or "").rstrip("/")
def run_monitor_check(): sender_instance = _normalize_env(EVOLUTION_SENDER_INSTANCE) or "Wander"
"""Executa o fluxo de verificação completo.""" url = f"{base_url}/message/sendText/{sender_instance}"
log_messages = []
whatsapp_status = "-" now = get_now()
email_status = "-" message_text = (
"MONITOR OK\n\n"
# Passo 1: Verificar Health Evolution API f"Data: {now.strftime('%d/%m/%Y')}\n"
try: f"Horario: {now.strftime('%H:%M:%S')}\n\n"
# Endpoint correto: /instance/connectionState/{instanceName} "• Evolution API: Online\n"
# Usa o nome da instância (EVOLUTION_SENDER_INSTANCE) e não o ID "• Webhook Instancia: Habilitado\n"
health_url = f"{EVOLUTION_API_URL}/instance/connectionState/{EVOLUTION_SENDER_INSTANCE}" "• Webhook N8N: Funcionando\n\n"
resp_health = requests.get(health_url, headers=get_headers(), timeout=10) "Todos os servicos operacionais."
)
if resp_health.status_code == 200:
# Validar se a instância está realmente conectada (state: open) payload = {"number": WHATSAPP_NUMBER, "text": message_text}
try: response = requests.post(url, json=payload, headers=get_headers(), timeout=10)
data = resp_health.json()
instance_data = data.get('instance', {}) if response.status_code in (200, 201):
state = instance_data.get('state') or data.get('state') return True, "WhatsApp de sucesso enviado."
return False, f"Falha ao enviar WhatsApp: {response.text}"
if state == 'open': except Exception as exc:
log_messages.append("✅ Evolution API Online") return False, f"Erro na requisicao WhatsApp: {exc}"
else:
# Estado não é 'open' (ex: close, closed, connecting) = ERRO!
error_msg = f"Evolution API Desconectada (State: {state})" def run_monitor_check():
log_messages.append(f"{error_msg}") log_messages = []
whatsapp_status = "-"
# Enviar email de erro email_status = "-"
email_ok, _ = send_email_error(error_msg)
email_status = "Sucesso" if email_ok else "Erro" missing_env = _required_env_missing()
if missing_env:
return False, log_messages, whatsapp_status, email_status log_messages.append(f"❌ Configuracao ausente no .env: {', '.join(missing_env)}")
return False, log_messages, whatsapp_status, email_status
except Exception as json_err:
# Se falhar ler JSON mas deu 200 OK, verificar se é HTML base_url = (_normalize_env(EVOLUTION_API_URL) or "").rstrip("/")
raw_text = resp_health.text.strip() sender_instance = _normalize_env(EVOLUTION_SENDER_INSTANCE) or "Wander"
if raw_text.startswith('<!doctype') or raw_text.startswith('<html'): webhook_n8n_url = _normalize_env(N8N_WEBHOOK_URL)
error_msg = "Evolution API retornou HTML (possível erro de autenticação)"
elif raw_text: # Passo 1: Health Evolution API
error_msg = "Evolution API retornou JSON inválido" try:
else: health_url = f"{base_url}/instance/connectionState/{sender_instance}"
error_msg = "Evolution API retornou resposta vazia" resp_health = requests.get(health_url, headers=get_headers(), timeout=10)
log_messages.append(f"{error_msg}") if resp_health.status_code == 200:
email_ok, _ = send_email_error(error_msg) try:
email_status = "Sucesso" if email_ok else "Erro" data = resp_health.json()
instance_data = data.get("instance", {})
return False, log_messages, whatsapp_status, email_status state = instance_data.get("state") or data.get("state")
else:
error_msg = f"Evolution API Offline. Status: {resp_health.status_code}" if state == "open":
log_messages.append(f"{error_msg}") log_messages.append("✅ Evolution API Online")
else:
# Tenta enviar email de erro error_msg = f"Evolution API Desconectada (State: {state})"
email_ok, _ = send_email_error(error_msg) log_messages.append(f"{error_msg}")
email_status = "Sucesso" if email_ok else "Erro" email_ok, _ = send_email_error(error_msg)
email_status = "Sucesso" if email_ok else "Erro"
return False, log_messages, whatsapp_status, email_status return False, log_messages, whatsapp_status, email_status
except Exception:
except Exception as e: raw_text = (resp_health.text or "").strip().lower()
error_msg = f"Erro ao conectar na Evolution API: {str(e)}" if raw_text.startswith("<!doctype") or raw_text.startswith("<html"):
log_messages.append(f"{error_msg}") error_msg = "Evolution API retornou HTML (possivel erro de autenticacao)"
elif raw_text:
email_ok, _ = send_email_error(error_msg) error_msg = "Evolution API retornou JSON invalido"
email_status = "Sucesso" if email_ok else "Erro" else:
error_msg = "Evolution API retornou resposta vazia"
return False, log_messages, whatsapp_status, email_status
log_messages.append(f"{error_msg}")
# Passo 1.5: Verificar se o Webhook da Instância está habilitado email_ok, _ = send_email_error(error_msg)
try: email_status = "Sucesso" if email_ok else "Erro"
webhook_url = f"{EVOLUTION_API_URL}/webhook/find/{EVOLUTION_SENDER_INSTANCE}" return False, log_messages, whatsapp_status, email_status
resp_webhook_config = requests.get(webhook_url, headers=get_headers(), timeout=15) else:
error_msg = f"Evolution API Offline. Status: {resp_health.status_code}"
if resp_webhook_config.status_code == 200: log_messages.append(f"{error_msg}")
webhook_data = resp_webhook_config.json() email_ok, _ = send_email_error(error_msg)
# Verificar se enabled é True email_status = "Sucesso" if email_ok else "Erro"
webhook_enabled = webhook_data.get('enabled', False) return False, log_messages, whatsapp_status, email_status
webhook_url_configured = webhook_data.get('url', 'N/A') except Exception as exc:
error_msg = f"Erro ao conectar na Evolution API: {exc}"
if webhook_enabled: log_messages.append(f"{error_msg}")
log_messages.append("✅ Webhook Instância OK") email_ok, _ = send_email_error(error_msg)
else: email_status = "Sucesso" if email_ok else "Erro"
error_msg = f"Webhook da Instância DESABILITADO" return False, log_messages, whatsapp_status, email_status
log_messages.append(f"{error_msg}")
# Passo 1.5: Webhook da instancia
email_ok, _ = send_email_error(error_msg) try:
email_status = "Sucesso" if email_ok else "Erro" webhook_url = f"{base_url}/webhook/find/{sender_instance}"
resp_webhook_config = requests.get(webhook_url, headers=get_headers(), timeout=15)
return False, log_messages, whatsapp_status, email_status
else: if resp_webhook_config.status_code == 200:
# Se não conseguir verificar, apenas loga aviso mas continua webhook_data = resp_webhook_config.json()
log_messages.append(f"⚠️ Não foi possível verificar webhook da instância (Status: {resp_webhook_config.status_code})") webhook_enabled = webhook_data.get("enabled", False)
except Exception as e: if webhook_enabled:
# Se falhar a verificação do webhook, loga aviso mas continua log_messages.append("✅ Webhook Instancia OK")
log_messages.append(f"⚠️ Erro ao verificar webhook da instância: {str(e)[:50]}") else:
error_msg = "Webhook da Instancia DESABILITADO"
# Passo 2: Testar Webhook N8N log_messages.append(f"{error_msg}")
try: email_ok, _ = send_email_error(error_msg)
# Nota: O fluxo original faz um POST simples email_status = "Sucesso" if email_ok else "Erro"
resp_webhook = requests.post(N8N_WEBHOOK_URL, json={"check": "ping"}, timeout=10) return False, log_messages, whatsapp_status, email_status
else:
if resp_webhook.status_code == 200: log_messages.append(
log_messages.append("✅ Webhook N8N OK") f"⚠️ Nao foi possivel verificar webhook da instancia "
else: f"(Status: {resp_webhook_config.status_code})"
error_msg = f"Webhook N8N falhou. Status: {resp_webhook.status_code}" )
log_messages.append(f"{error_msg}") except Exception as exc:
log_messages.append(f"⚠️ Erro ao verificar webhook da instancia: {str(exc)[:80]}")
email_ok, _ = send_email_error(error_msg)
email_status = "Sucesso" if email_ok else "Erro" # Passo 2: Teste webhook N8N
try:
return False, log_messages, whatsapp_status, email_status resp_webhook = requests.post(webhook_n8n_url, json={"check": "ping"}, timeout=10)
if resp_webhook.status_code == 200:
except Exception as e: log_messages.append("✅ Webhook N8N OK")
error_msg = f"Erro ao conectar no Webhook N8N: {str(e)}" else:
log_messages.append(f"{error_msg}") error_msg = f"Webhook N8N falhou. Status: {resp_webhook.status_code}"
log_messages.append(f"{error_msg}")
email_ok, _ = send_email_error(error_msg) email_ok, _ = send_email_error(error_msg)
email_status = "Sucesso" if email_ok else "Erro" email_status = "Sucesso" if email_ok else "Erro"
return False, log_messages, whatsapp_status, email_status
return False, log_messages, whatsapp_status, email_status except Exception as exc:
error_msg = f"Erro ao conectar no Webhook N8N: {exc}"
# Passo 3: Se chegou aqui, tudo OK -> Enviar WhatsApp log_messages.append(f"{error_msg}")
# Se está tudo OK, email de erro não é enviado, então mantemos email_status como "-" ou podemos por "N/A" email_ok, _ = send_email_error(error_msg)
# O usuário pediu "Sucesso ou Error". Se não enviou nada, talvez "-" seja melhor que "Error". email_status = "Sucesso" if email_ok else "Erro"
return False, log_messages, whatsapp_status, email_status
success, msg = send_whatsapp_success()
if success: # Passo 3: Notificacao de sucesso via WhatsApp
log_messages.append(f"{msg}") success, msg = send_whatsapp_success()
whatsapp_status = "Sucesso" if success:
return True, log_messages, whatsapp_status, email_status log_messages.append(f"{msg}")
else: whatsapp_status = "Sucesso"
# Se falhar enviar o whats, é um erro também? return True, log_messages, whatsapp_status, email_status
whatsapp_status = "Erro"
whatsapp_status = "Erro"
# O fluxo original manda email de erro se o check falhar. error_msg = f"Servicos online, mas falha ao enviar WhatsApp: {msg}"
# Se o envio do whats falhar, vamos mandar email log_messages.append(f"⚠️ {error_msg}")
error_msg = f"Serviços Online, mas falha ao enviar WhatsApp: {msg}" email_ok, _ = send_email_error(error_msg)
log_messages.append(f"⚠️ {error_msg}") email_status = "Sucesso" if email_ok else "Erro"
return False, log_messages, whatsapp_status, email_status
email_ok, _ = send_email_error(error_msg)
email_status = "Sucesso" if email_ok else "Erro"
def diagnose_n8n_webhook():
return False, log_messages, whatsapp_status, email_status try:
url = _normalize_env(N8N_WEBHOOK_URL)
def diagnose_n8n_webhook(): now = get_now()
"""Realiza um teste detalhado do Webhook N8N para diagnóstico.""" payload = {"check": "diagnosis_ping", "timestamp": str(now)}
try:
url = N8N_WEBHOOK_URL log = {
now = get_now() "url": url,
payload = {"check": "diagnosis_ping", "timestamp": str(now)} "method": "POST",
"payload_sent": payload,
# Preparar log "status_code": None,
log = { "response_body": None,
"url": url, "headers_received": None,
"method": "POST", "error": None,
"payload_sent": payload, }
"status_code": None,
"response_body": None, if not url:
"headers_received": None, log["error"] = "N8N_WEBHOOK_URL nao configurada no .env"
"error": None return False, log
}
response = requests.post(url, json=payload, timeout=10)
response = requests.post(url, json=payload, timeout=10) log["status_code"] = response.status_code
log["response_body"] = response.text
log["status_code"] = response.status_code log["headers_received"] = dict(response.headers)
log["response_body"] = response.text return response.status_code == 200, log
log["headers_received"] = dict(response.headers) except Exception as exc:
return False, {
if response.status_code == 200: "url": _normalize_env(N8N_WEBHOOK_URL),
return True, log "method": "POST",
else: "payload_sent": None,
return False, log "status_code": None,
"response_body": None,
except Exception as e: "headers_received": None,
log["error"] = str(e) "error": str(exc),
return False, log }
if __name__ == "__main__":
# Teste rápido se rodar direto if __name__ == "__main__":
status, logs, wa_status, em_status = run_monitor_check() status, logs, wa_status, em_status = run_monitor_check()
print(f"Status: {status}") print(f"Status: {status}")
print(f"WhatsApp: {wa_status} | Email: {em_status}") print(f"WhatsApp: {wa_status} | Email: {em_status}")
print("\n".join(logs)) print("\n".join(logs))