From d5df0e3f05538b3ec2d2b48ab9327f86abcc21c6 Mon Sep 17 00:00:00 2001 From: minguezsanzjuanjose Date: Sun, 4 Oct 2026 00:48:29 +0200 Subject: [PATCH] 04-oct: encender_sobremesa escalera WoL->regleta->ciclo (Power On Loss validado) + doc --- CHANGELOG_INFRA.md | 9 +++ changelog_infra.json | 12 ++++ docs/PROTOCOLO_ENCENDIDO_REMOTO_SSH.md | 19 ++--- scripts/encender_sobremesa.py | 98 ++++++++++++++------------ 4 files changed, 82 insertions(+), 56 deletions(-) diff --git a/CHANGELOG_INFRA.md b/CHANGELOG_INFRA.md index f45be6a..bce90d0 100644 --- a/CHANGELOG_INFRA.md +++ b/CHANGELOG_INFRA.md @@ -15,6 +15,7 @@ - **2026-10-04-instalador-de-dependencias-python-plugin-omniroute-autostart** [scripts] Instalador de dependencias Python + plugin omniroute-autostart + comparativa equipos (aplicado en: portatil) - **2026-10-04-fix-tareas-programadas-userdomain-computername-workgroup-ssh** [scripts] Fix tareas programadas: USERDOMAIN->COMPUTERNAME (workgroup/SSH) (aplicado en: portatil) - **2026-10-04-sobremesa-instalados-voicestudio-autohotkey-v2-tarea-superwh** [scripts] Sobremesa: instalados VoiceStudio + AutoHotkey v2 + tarea SuperWhisper Enter (aplicado en: portatil) +- **2026-10-04-protocolo-encendido-sobremesa-validado-wol-falla-ciclo-regle** [servicios] Protocolo encendido sobremesa validado: WoL falla, ciclo regleta funciona (Power On Loss) (aplicado en: portatil) ## Historial @@ -50,6 +51,14 @@ - **Aplicado en**: portatil - **Detalle**: Via SSH desde el portatil. VoiceStudio 0.5.6 (per-user en %LOCALAPPDATA%\Programs\VoiceStudio, instalador GitHub debpalash/VoiceStudio /S). AutoHotkey v2 (winget AutoHotkey.AutoHotkey). Tarea programada 'SuperWhisper Enter' (AtLogOn, hidden) -> AutoHotkey64.exe + scripts/superwhisper_enter.ahk. Nota: el sobremesa tiene RTX 4070 (12GB) -> VoiceStudio usara GPU; requiere abrir la app para levantar backend 3900 y crear perfiles de voz. +### 2026-10-04 · Protocolo encendido sobremesa validado: WoL falla, ciclo regleta funciona (Power On Loss) +- **id**: `2026-10-04-protocolo-encendido-sobremesa-validado-wol-falla-ciclo-regle` +- **Equipo**: portatil +- **Categoria**: servicios +- **Transferible**: si +- **Aplicado en**: portatil +- **Detalle**: Prueba 04-oct: apagado simple OK; WoL desde portatil NO responde (doble NAT .50->.1); ciclo regleta (apagar 1min + encender) arranca el PC solo (BIOS Restore on AC Power Loss = Power On). encender_sobremesa.py actualizado con la escalera WoL->regleta->ciclo-regleta. Doc PROTOCOLO_ENCENDIDO_REMOTO_SSH.md actualizado. + ### 2026-10-03 · SuperWhisper Enter: AHK F13 boton auxiliar Logitech + tarea programada - **id**: `2026-10-03-superwhisper-enter-ahk-f13-boton-auxiliar-logitech-tarea-pro` - **Equipo**: portatil diff --git a/changelog_infra.json b/changelog_infra.json index 184631e..79f7269 100644 --- a/changelog_infra.json +++ b/changelog_infra.json @@ -423,6 +423,18 @@ "portatil" ], "detalle": "Via SSH desde el portatil. VoiceStudio 0.5.6 (per-user en %LOCALAPPDATA%\\Programs\\VoiceStudio, instalador GitHub debpalash/VoiceStudio /S). AutoHotkey v2 (winget AutoHotkey.AutoHotkey). Tarea programada 'SuperWhisper Enter' (AtLogOn, hidden) -> AutoHotkey64.exe + scripts/superwhisper_enter.ahk. Nota: el sobremesa tiene RTX 4070 (12GB) -> VoiceStudio usara GPU; requiere abrir la app para levantar backend 3900 y crear perfiles de voz." + }, + { + "id": "2026-10-04-protocolo-encendido-sobremesa-validado-wol-falla-ciclo-regle", + "fecha": "2026-10-04", + "equipo": "portatil", + "categoria": "servicios", + "titulo": "Protocolo encendido sobremesa validado: WoL falla, ciclo regleta funciona (Power On Loss)", + "transferible": true, + "aplicado_en": [ + "portatil" + ], + "detalle": "Prueba 04-oct: apagado simple OK; WoL desde portatil NO responde (doble NAT .50->.1); ciclo regleta (apagar 1min + encender) arranca el PC solo (BIOS Restore on AC Power Loss = Power On). encender_sobremesa.py actualizado con la escalera WoL->regleta->ciclo-regleta. Doc PROTOCOLO_ENCENDIDO_REMOTO_SSH.md actualizado." } ] } diff --git a/docs/PROTOCOLO_ENCENDIDO_REMOTO_SSH.md b/docs/PROTOCOLO_ENCENDIDO_REMOTO_SSH.md index 2a2c7e2..7896b6b 100644 --- a/docs/PROTOCOLO_ENCENDIDO_REMOTO_SSH.md +++ b/docs/PROTOCOLO_ENCENDIDO_REMOTO_SSH.md @@ -22,19 +22,20 @@ Fecha: 03-oct-2026. Objetivo: **encender el sobremesa estando apagado y conectar ``` `offline` = apagado. (Desde la red `.1` también vale `ping 192.168.1.239`.) -**2. Si está apagado → encender la regleta** (comando Alexa vía Home Assistant) -```powershell -python C:\Users\juanm\Documents\GitHub\biblioteca_negocio_prolongo\scripts\ha_alexa.py command "enciende regleta" -``` +**2. Escalera de intentos** (en orden; comprobar el estado tras cada uno): -**3. Esperar 3 minutos.** +1. **Wake-on-LAN** — magic packet a la MAC `74:56:3C:CB:0E:CE`. + > Desde el portátil (`.50`) el magic packet **no cruza** a `.1` por el doble NAT → normalmente **falla**. Solo funcionaría desde un equipo en la red `.1`. +2. **Encender la regleta** (comando Alexa vía Home Assistant): + ```powershell + python C:\Users\juanm\Documents\GitHub\biblioteca_negocio_prolongo\scripts\ha_alexa.py command "enciende regleta" + ``` +3. **Ciclo de regleta** (el **fiable**): apagar la regleta, esperar **1 min**, y volver a encenderla. Con `Restore on AC Power Loss = Power On` en BIOS, el PC **arranca solo**. -**4. Volver a comprobar el estado.** Si está encendido → **listo**. +**3. Informar** (aviso voz Carolina) tras cada comprobación. -**5. Si sigue apagado → intentar Wake-on-LAN** (magic packet a la MAC `74:56:3C:CB:0E:CE`). -> Nota: desde el portátil (`.50`) el magic packet **no llega** a `.1` por el doble NAT. Solo funcionaría desde un equipo en la red `.1`. El método fiable es la **regleta** (+ BIOS `Restore on AC Power Loss = Power On`). +> **Resultado de la prueba (04-oct-2026):** apagado simple OK; **WoL NO funcionó**; **ciclo de regleta SÍ** (arrancó solo, confirma `Power On Loss`). Es la vía buena para el sobremesa. -**6. Esperar 3 minutos, comprobar e informar.** **7. Conectar a PowerShell:** ```powershell diff --git a/scripts/encender_sobremesa.py b/scripts/encender_sobremesa.py index a3c3215..8b4196e 100644 --- a/scripts/encender_sobremesa.py +++ b/scripts/encender_sobremesa.py @@ -2,20 +2,16 @@ # -*- coding: utf-8 -*- """encender_sobremesa.py — Protocolo de encendido remoto del sobremesa. -Pasos (protocolo acordado): - 0. Estado de la regleta (best-effort, si hay acceso al Tapo). - 1. Comprobar si el PC esta apagado (Tailscale). - 2. Si esta apagado -> encender la regleta con un comando a Alexa (via Home Assistant). - 3. Esperar 3 min. - 4. Volver a comprobar. Si esta encendido -> fin. - 5. Si sigue apagado -> intentar Wake-on-LAN (best-effort). - 6. Esperar 3 min, comprobar e informar. - -Al terminar cada comprobacion emite un aviso de voz (Carolina) para que el usuario -pueda hacer otras cosas mientras tanto. +Escalera de intentos (acordada): + 0. Estado de la regleta (best-effort). + 1. Si el PC esta apagado -> intento 1: Wake-on-LAN. + 2. Si no responde -> intento 2: encender la regleta (comando Alexa via Home Assistant). + 3. Si no responde -> intento 3: apagar la regleta 1 min y volver a encenderla + (BIOS 'Restore on AC Power Loss = Power On' -> arranca solo). + 4. Informar por voz (Carolina) tras cada comprobacion. Uso: - python scripts/encender_sobremesa.py [--espera 180] [--no-voz] + python scripts/encender_sobremesa.py [--espera 120] [--no-voz] """ from __future__ import annotations @@ -36,13 +32,11 @@ import infra_paths # noqa: E402 TS_EXE = os.path.join(os.environ.get("ProgramFiles", r"C:\Program Files"), "Tailscale", "tailscale.exe") NODO = "desktop-m8se61g" -TAILSCALE_IP = "100.75.115.29" +COS_ENCENDER = "enciende regleta" +COS_APAGAR = "apaga regleta" MAC = "74:56:3C:CB:0E:CE" -COMANDO_REGLETA = "enciende regleta" -# --------------------------------------------------------------- estado del PC - def pc_encendido() -> bool | None: """True/False segun Tailscale. None si no se puede determinar.""" try: @@ -55,15 +49,12 @@ def pc_encendido() -> bool | None: return None -# --------------------------------------------------------------- regleta (Tapo) - def estado_regleta() -> bool | None: """Best-effort: True/False si se puede consultar el Tapo; None si no.""" try: from PyP100 import PyP100 as PP except Exception: return None - # credenciales hardcodeadas en un script existente del repo de negocio repo = infra_paths.biblioteca_repo() creds = None for f in glob.glob(str(repo / "scripts" / "protocolo_apagado*.py")) + glob.glob(str(_SCRIPTS_DIR / "protocolo_apagado*.py")): @@ -86,28 +77,29 @@ def estado_regleta() -> bool | None: return None -# --------------------------------------------------------------- Alexa / HA - -def encender_regleta() -> bool: - """Envia 'enciende regleta' a Alexa vía Home Assistant.""" +def _comando_alexa(texto: str) -> bool: infra_paths.bootstrap_biblioteca_paths() try: from ha_alexa import command - - return command(COMANDO_REGLETA) + return command(texto) except Exception as e: print(f"[encender_sobremesa] Error llamando a HA: {e}", file=sys.stderr) return False -# --------------------------------------------------------------- WoL +def encender_regleta() -> bool: + return _comando_alexa(COS_ENCENDER) + + +def apagar_regleta() -> bool: + return _comando_alexa(COS_APAGAR) + def wol() -> None: """Magic packet (best-effort). Desde .50 no cruza a .1; se intenta igualmente.""" import socket - paquete = b"\xff" * 6 + bytes.fromhex(MAC.replace(":", "")) * 16 - for destino in (f"{TAILSCALE_IP.split('.')[0]}.255", "255.255.255.255", "192.168.1.255", "192.168.50.255"): + for destino in ("192.168.1.255", "192.168.1.239", "255.255.255.255", "192.168.50.255"): try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) @@ -118,7 +110,15 @@ def wol() -> None: print(f" magic packet -> {destino}:9 ERROR {e}") -# --------------------------------------------------------------- voz +def esperar_encendido(segundos: int) -> bool: + t = 0 + while t < segundos: + if pc_encendido(): + return True + time.sleep(10) + t += 10 + return False + def aviso(texto: str, voz: bool = True) -> None: print(f"[aviso] {texto}") @@ -131,11 +131,9 @@ def aviso(texto: str, voz: bool = True) -> None: pass -# --------------------------------------------------------------- protocolo - def main() -> int: ap = argparse.ArgumentParser(description="Encendido remoto del sobremesa.") - ap.add_argument("--espera", type=int, default=180, help="Segundos de espera entre comprobaciones (defecto 180).") + ap.add_argument("--espera", type=int, default=120, help="Segundos por intento (defecto 120).") ap.add_argument("--no-voz", action="store_true", help="Sin avisos de voz.") args = ap.parse_args() voz = not args.no_voz @@ -149,24 +147,30 @@ def main() -> int: aviso("El sobremesa ya estaba encendido.", voz) return 0 - print(f"-> Encendiendo regleta (Alexa: '{COMANDO_REGLETA}')... {encender_regleta()}") - print(f"-> Esperando {args.espera}s...") - time.sleep(args.espera) - - if pc_encendido(): - aviso("El sobremesa se ha encendido correctamente con la regleta.", voz) - return 0 - - print("-> Sigue apagado; intentando Wake-on-LAN (best-effort)...") + # Intento 1 - Wake-on-LAN + print(f"-> Intento 1: Wake-on-LAN...") wol() - print(f"-> Esperando {args.espera}s...") - time.sleep(args.espera) - - if pc_encendido(): - aviso("El sobremesa se ha encendido tras el Wake on LAN.", voz) + if esperar_encendido(args.espera): + aviso("El sobremesa se ha encendido con Wake on LAN.", voz) return 0 - aviso("No se ha podido encender el sobremesa ni con la regleta ni con Wake on LAN.", voz) + # Intento 2 - encender regleta + print("-> Intento 2: encender regleta (Alexa)...") + encender_regleta() + if esperar_encendido(args.espera): + aviso("El sobremesa se ha encendido al dar corriente la regleta.", voz) + return 0 + + # Intento 3 - ciclo de regleta (Power On Loss) + print("-> Intento 3: apagar regleta 1 min y volver a encender (Power On Loss)...") + apagar_regleta() + time.sleep(60) + encender_regleta() + if esperar_encendido(args.espera): + aviso("El sobremesa se ha encendido tras el ciclo de regleta. Power On Loss funciona.", voz) + return 0 + + aviso("No se ha podido encender el sobremesa ni con WoL ni con la regleta.", voz) return 1