Force Sleep en macOS — LaunchAgent con pmset sleepnow Dejar en suspensión un Mac de no es tan fácil como antes sobre todo si es un equipo estático con discos externos. Discos de backup externos, el micro exterrnbo, los altavoces,... Y él no dejar que descanse tu Mac, le envejece prematuramente. Es como las personas necesitan dormir descansar. Solución para forzar el sleep del Mac ignorando assertions de bluetoothd , powerd y otros procesos que bloquean el sleep normal. Variables de configuración Edita solo este bloque antes de ejecutar cualquier comando. O usa sed para reemplazar en bloque (ver sección al final). MAC_USER="abkrim" # tu usuario macOS IDLE_MINUTES=30 # minutos de inactividad antes de dormir CHECK_INTERVAL=300 # cada cuántos segundos comprueba (300 = 5 min) SCRIPT_PATH="/Users/$MAC_USER/Library/Scripts/force-sleep.sh" PLIST_PATH="/Users/$MAC_USER/Library/LaunchAgents/com.user.forcesleep.plist" LABEL="com.user.forcesleep" El problema pmset sleep 30 respeta las sleep assertions : procesos como bluetoothd o powerd pueden decirle al sistema "no te duermas" y el Mac ignora el timer configurado. # Diagnóstico: ver qué está bloqueando el sleep pmset -g assertions # El output típico del problema: # sleep 0 (sleep prevented by bluetoothd, powerd, cloudd...) pmset sleepnow ignora esas assertions y duerme el Mac sin negociación. Solución: script + LaunchAgent 1 — Crear el script gral cat > "$SCRIPT_PATH" << 'EOF' #!/bin/bash # Rutas absolutas — los LaunchAgents arrancan sin $PATH normal IOREG=/usr/sbin/ioreg PMSET=/usr/bin/pmset AWK=/usr/bin/awk IDLE=$($IOREG -c IOHIDSystem | $AWK '/HIDIdleTime/ {print int($NF/1000000000); exit}') # Salir si IDLE está vacío (evita errores de comparación) [[ -z "$IDLE" ]] && exit 0 if [ "$IDLE" -ge IDLE_SECONDS ]; then $PMSET sleepnow fi EOF # Sustituir IDLE_SECONDS con el valor real (30 min = 1800 s) IDLE_SECONDS=$(( IDLE_MINUTES * 60 )) sed -i '' "s/IDLE_SECONDS/$IDLE_SECONDS/" "$SCRIPT_PATH" chmod +x "$SCRIPT_PATH" ¿Por qué rutas absolutas? Los LaunchAgents arrancan con un $PATH mínimo ( /usr/bin:/bin ). Sin ruta absoluta, ioreg y pmset dan Error 127 (command not found). 2 — Verificar que los binarios existen which ioreg pmset awk # Esperado: # /usr/sbin/ioreg # /usr/bin/pmset # /usr/bin/awk 3 — Crear el plist ⚠️ El nombre del archivo debe terminar en .plist . Sin la extensión o con sufijos extra (ej. .plist-e ) macOS rechaza el agente con Error 127. cat > "$PLIST_PATH" << EOF Label $LABEL ProgramArguments /bin/bash $SCRIPT_PATH StartInterval $CHECK_INTERVAL RunAtLoad EOF 4 — Cargar el agente launchctl load "$PLIST_PATH" # Verificar: la segunda columna debe ser 0 (sin error) launchctl list | grep forcesleep Gestión del agente # Desactivar (sin eliminar) launchctl unload "$PLIST_PATH" # Reactivar launchctl load "$PLIST_PATH" # Eliminar completamente launchctl unload "$PLIST_PATH" rm "$SCRIPT_PATH" rm "$PLIST_PATH" # Probar el script manualmente bash "$SCRIPT_PATH" # Ver idle time actual (en segundos) /usr/sbin/ioreg -c IOHIDSystem | /usr/bin/awk '/HIDIdleTime/ {print int($NF/1000000000); exit}' Diagnóstico de errores comunes Error Causa Solución Error 127 Binario no encontrado por $PATH vacío Usar rutas absolutas en el script Error 127 en LaunchControl Nombre del plist sin extensión o con sufijo extra Recrear con nombre exacto *.plist IDLE vacío ioreg no devuelve HIDIdleTime Comprobar which ioreg , verificar ruta Sleep no ocurre pmset sleep respeta assertions Usar pmset sleepnow en su lugar Adaptar a otro usuario con sed Para usar esta guía en otra máquina, reemplaza el usuario en bloque: # Reemplazar "abkrim" por el nuevo usuario en todos los comandos sed 's/abkrim/NUEVO_USUARIO/g' force-sleep-mac.md > force-sleep-mac-custom.md O directamente al ejecutar, exporta las variables al inicio de tu sesión de terminal y copia/pega los bloques de código — las variables $MAC_USER , $SCRIPT_PATH , etc. se resolverán solas. Cómo funciona (resumen) LaunchAgent (cada 5 min) │ ▼ force-sleep.sh │ ├─ Lee idle time desde IOHIDSystem (ioreg) │ ├─ ¿IDLE >= 1800s? ──No──► exit 0 │ └──Sí──► pmset sleepnow ◄── ignora bluetoothd, powerd, etc. Aviso Esta documentación y su contenido, no implica que funcione en tu caso o determinados casos. También implica que tienes conocimientos sobre lo que trata, y que en cualquier caso tienes copias de seguridad. El contenido el contenido se entrega, tal y como está, sin que ello implique ningún obligación ni responsabilidad por parte de Castris Si necesitas soporte profesional puedes contratar con Castris soporte profesional .