superguardado: comando limpieza (limpia procesos atascados de la Pi) + limpiar.py

This commit is contained in:
minguezsanzjuanjose
2026-08-02 22:49:59 +02:00
parent 33e50ca274
commit 5d232cd830
7 changed files with 339 additions and 1 deletions

1
.obsidian/app.json vendored Normal file
View File

@@ -0,0 +1 @@
{}

1
.obsidian/appearance.json vendored Normal file
View File

@@ -0,0 +1 @@
{}

33
.obsidian/core-plugins.json vendored Normal file
View File

@@ -0,0 +1,33 @@
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"footnotes": false,
"properties": true,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"bookmarks": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": true,
"bases": true,
"webviewer": false
}

22
.obsidian/graph.json vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"collapse-filter": true,
"search": "",
"showTags": false,
"showAttachments": false,
"hideUnresolved": false,
"showOrphans": true,
"collapse-color-groups": true,
"colorGroups": [],
"collapse-display": true,
"showArrow": false,
"textFadeMultiplier": 0,
"nodeSizeMultiplier": 1,
"lineSizeMultiplier": 1,
"collapse-forces": true,
"centerStrength": 0.518713248970312,
"repelStrength": 10,
"linkStrength": 1,
"linkDistance": 250,
"scale": 1,
"close": false
}

189
.obsidian/workspace.json vendored Normal file
View File

@@ -0,0 +1,189 @@
{
"main": {
"id": "926bba7b6257cb83",
"type": "split",
"children": [
{
"id": "d8f7c226097458c7",
"type": "tabs",
"children": [
{
"id": "72506070fed1a695",
"type": "leaf",
"state": {
"type": "graph",
"state": {},
"icon": "lucide-git-fork",
"title": "Vista gráfica"
}
}
]
}
],
"direction": "vertical"
},
"left": {
"id": "84a364de2999912b",
"type": "split",
"children": [
{
"id": "8bab02b5105eeb5b",
"type": "tabs",
"children": [
{
"id": "487dc72c4c2ad06f",
"type": "leaf",
"state": {
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical",
"autoReveal": false,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-folder-closed",
"title": "Explorador de archivos"
}
},
{
"id": "245580e4caa54b56",
"type": "leaf",
"state": {
"type": "search",
"state": {
"query": "",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
},
"icon": "lucide-search",
"title": "Buscar"
}
},
{
"id": "e78680f9daec255d",
"type": "leaf",
"state": {
"type": "bookmarks",
"state": {
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-bookmark",
"title": "Marcadores"
}
}
]
}
],
"direction": "horizontal",
"width": 300
},
"right": {
"id": "2a664eeb01bb6a0e",
"type": "split",
"children": [
{
"id": "7d195b329221cd02",
"type": "tabs",
"children": [
{
"id": "1ebc95b7268f14a7",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-coming-in",
"title": "Enlaces entrantes"
}
},
{
"id": "a3196bc4461f5957",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"linksCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-going-out",
"title": "Enlaces salientes"
}
},
{
"id": "464b357dcc7110d9",
"type": "leaf",
"state": {
"type": "tag",
"state": {
"sortOrder": "frequency",
"useHierarchy": true,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-tags",
"title": "Etiquetas"
}
},
{
"id": "fce335174b5a3979",
"type": "leaf",
"state": {
"type": "all-properties",
"state": {
"sortOrder": "frequency",
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-archive",
"title": "Todas las propiedades"
}
},
{
"id": "139ea07527216a59",
"type": "leaf",
"state": {
"type": "outline",
"state": {
"followCursor": false,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-list",
"title": "Esquema"
}
}
]
}
],
"direction": "horizontal",
"width": 300,
"collapsed": true
},
"left-ribbon": {
"hiddenItems": {
"switcher:Abrir selector rápido": false,
"graph:Abrir vista gráfica": false,
"canvas:Crear nuevo lienzo": false,
"daily-notes:Abrir la nota de hoy": false,
"templates:Insertar plantilla": false,
"command-palette:Abrir paleta de comandos": false,
"bases:Crear nueva base": false
}
},
"active": "72506070fed1a695",
"lastOpenFiles": [
"vigilancia/__pycache__/limpiar.cpython-313.pyc",
"vigilancia/limpiar.py"
]
}

82
vigilancia/limpiar.py Normal file
View File

@@ -0,0 +1,82 @@
#!/usr/bin/env python3
"""Limpieza de procesos de la Pi: mata procesos zombie/atascados, reinicia servicios si es necesario."""
import subprocess
import os
import sys
import time
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import config
def sh(cmd):
try:
return subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=15).stdout.strip()
except Exception:
return ""
def limpiar():
informe = []
# 1. Procesos Python atascados (CPU > 50% durante >60s)
ps = sh("ps aux | grep python3 | grep -v grep")
for linea in ps.splitlines():
if not linea: continue
parts = linea.split()
try:
cpu = float(parts[2])
pid = parts[1]
cmd = " ".join(parts[10:])
if cpu > 50 and "minipc" in cmd:
informe.append(f"Matando proceso atascado PID {pid} ({cpu}% CPU): {cmd[:50]}")
sh(f"kill -9 {pid}")
except (IndexError, ValueError):
pass
# 2. Zombie processes
zombies = sh("ps aux | awk '$8==\"Z\" {print $2}'")
for z in zombies.splitlines():
if z.strip():
informe.append(f"Zombie PID {z.strip()} limpiado")
sh(f"kill -9 {z.strip()}")
# 3. Procesos python viejos (>2h, sin ser servicios principales)
ps2 = sh("ps aux | grep python3 | grep -v grep")
for linea in ps2.splitlines():
if not linea: continue
parts = linea.split()
try:
pid = parts[1]
starttime = parts[8]
cmd = " ".join(parts[10:])
if "tv_api" not in cmd and "pi_bot" not in cmd and "http.server" not in cmd:
if "python" in cmd.lower() or "vigilancia" in cmd.lower():
informe.append(f"Proceso residual PID {pid}: {cmd[:60]}")
except (IndexError, ValueError):
pass
# 4. Limpiar cache del sistema
sh("echo 'raspberry' | sudo -S sync")
sh("echo 'raspberry' | sudo -S sh -c 'echo 3 > /proc/sys/vm/drop_caches'")
informe.append("Caché del sistema limpiado")
# 5. Verificar servicios
for svc in ["tv-api", "pi-bot"]:
st = sh(f"systemctl is-active {svc}")
if st != "active":
informe.append(f"⚠️ Servicio {svc} no activo: {st}")
sh(f"echo 'raspberry' | sudo -S systemctl restart {svc}")
# 6. Estado final
temp = sh("vcgencmd measure_temp")
load = sh("cat /proc/loadavg | cut -d' ' -f1")
mem = sh("free -h | awk 'NR==2{print $2\" total, \"$7\" libre\"}'")
if not informe:
informe.append("✅ Todo limpio, sin procesos atascados")
informe.append(f"\nEstado: temp={temp} | load={load} | mem={mem}")
return "\n".join(informe)
if __name__ == "__main__":
print(limpiar())

View File

@@ -137,6 +137,15 @@ def procesar(texto, chat_id):
log(f"panorama: {r.stdout.strip()[-200:]}") log(f"panorama: {r.stdout.strip()[-200:]}")
except Exception as e: except Exception as e:
log(f"panorama error: {e}") log(f"panorama error: {e}")
elif t in ("limpieza", "/limpieza", "limpiar", "/limpiar"):
enviar("🧹 Ejecutando limpieza...", chat_id)
try:
from limpiar import limpiar
resultado = limpiar()
enviar(f"<pre>{resultado}</pre>", chat_id)
except Exception as e:
log(f"limpieza error: {e}")
enviar(f"❌ Error: {e}", chat_id)
elif t.startswith("youtube ") or t.startswith("/youtube "): elif t.startswith("youtube ") or t.startswith("/youtube "):
url = texto.split(" ", 1)[1].strip() url = texto.split(" ", 1)[1].strip()
if not url: if not url:
@@ -151,7 +160,8 @@ def procesar(texto, chat_id):
"<b>tv &lt;mensaje&gt;</b> — mensaje rápido a la tele\n" "<b>tv &lt;mensaje&gt;</b> — mensaje rápido a la tele\n"
"<b>alarma &lt;mensaje&gt;</b> — secuencia completa (sirena x3)\n" "<b>alarma &lt;mensaje&gt;</b> — secuencia completa (sirena x3)\n"
"<b>youtube &lt;URL&gt;</b> — reproduce YouTube y apaga al terminar\n" "<b>youtube &lt;URL&gt;</b> — reproduce YouTube y apaga al terminar\n"
"<b>panorama</b> — fotos de las cámaras", "<b>panorama</b> — fotos de las cámaras\n"
"<b>limpieza</b> — limpia procesos atascados de la Pi",
chat_id) chat_id)