Todavía no he encontrado nada, así que esperaba que tal vez alguien aquí tuviera una idea.
Quiero iniciar un evento basado en la batería de una computadora portátil Apple que alcanza cierto nivel de carga o cuando la batería está completamente cargada.
Sé que puedo hacer que algo se ejecute periódicamente, verificar el nivel de la batería y decidir qué hacer, pero prefiero el evento si es posible.
Bueno, esta pregunta es antigua, pero me encontré con una situación similar y quería ejecutar un atajo (con "Atajos de Siri") en macOS 12 con ciertos niveles de batería.
En lugar de un servicio en segundo plano, decidí que un script funcionaría mejor para mí, ya que debería encender y apagar mi toma de HomeKit a la que está conectado el cargador. (Pero solo mientras la MacBook está transcodificando una película)
De la respuesta de Joseph, tomé los bits que aún funcionan y creé un script Tcl que verifica el nivel de la batería cada minuto.
He creado un archivo llamado batt.tcl
con el siguiente contenido:
#!/usr/bin/env tclsh
set run 1
set last 0
set logs 1
set logfile "batt.log.txt"
set settingsfile batt.cfg
set min 15
set max 80
set delay 10000
# leave "nil"; we need a wake lock when we're charging. This is done using a call "caffeinate", waiting for another PID to be removed.
set wakeLock "nil"
proc log {message} {
if {$::logs != 1} {
return
}
set msg ""
append msg [clock format [clock seconds] -format "%d.%m.%Y %H:%M:%S"]
append msg ": "
append msg $message
set of1 [open $::logfile a]
puts $of1 $msg
close $of1
}
proc enableWakeLock {} {
if {$::wakeLock == "nil"} {
log "Enabling wake lock"
set ::wakeLock [open "|tclsh" r+]
set myProcess [pid $::wakeLock]
exec caffeinate -i -w $myProcess &
}
}
proc disableWakeLock {} {
if {$::wakeLock != "nil"} {
log "Disabling wake lock"
puts $::wakeLock "exit\n"
flush $::wakeLock
close $::wakeLock
set ::wakeLock "nil"
}
}
proc replaceAll {input lookup replacement} {
set offs 0
set mapping [list $lookup $replacement]
while {$offs != -1} {
set input [string map $mapping $input]
set offs [string first $lookup $input]
}
return $input
}
proc loadSettings {} {
if {[file exists $::settingsfile]} {
set if1 [open $::settingsfile]
set data [read $if1]
close $if1
set data [string map [list \t " " \n " " \r " "] $data]
set data [replaceAll $data " " " "]
set data [string trim $data " "]
set lines [split $data " "]
set id ""
foreach line $lines {
if {[string index $line 0] != "#"} {
if {[string length $id] == 0} {
set id $line
} else {
switch -exact -- $id {
"low:" {
set ::min $line
set id ""
}
"high:" {
set ::max $line
set id ""
}
"logs:" {
set ::logs $line
set id ""
}
"logfile:" {
set ::logfile $line
set id ""
}
default {
puts "Unknown config option <$id>. Aborting."
exit
}
}
}
}
}
} else {
puts -nonewline "Generating settings file"
flush stdout
set of1 [open $::settingsfile w]
puts $of1 [list "low:" $::min]
puts $of1 [list "high:" $::max]
puts $of1 [list "logfile:" $::logfile]
puts -nonewline $of1 [list "logs:" $::logs]
flush $of1
close $of1
puts ", done."
}
if {$::logs != 1 && $::logs != 0} {
set msg "Weird \"logs:\" setting: must be 1 or 0. Aborting."
puts $msg
exit
}
if {$::min >= $::max} {
set msg "Weird configuration: low charge ($::min) is equal or higher that high charge ($::max). Aborting."
puts $msg
exit
}
}
proc waypointSearch {input waypoints endwaypoint} {
set offs 0
set len 0
foreach wp $waypoints {
set len [string length $wp]
set offs [string first $wp $input $offs]
if {$offs < 0} {
puts "Waypoint \"$wp\" not found."
}
# puts "WP: <$wp> $offs $len"
}
set eoffs [string first $endwaypoint $input $offs]
if {$eoffs < 0} {
puts "Waypoint \"$endwaypoint\" not found."
}
return [string range $input [expr $offs + $len] [expr $eoffs - 1]]
}
loadSettings
set msg "Starting with settngs for low: $min and high: $max."
puts -nonewline "\n\nlow: $min, high: $max"
log $msg
while {$run == 1} {
set input [exec ioreg -l]
set lvl [waypointSearch $input [list "AppleSmartBattery " "\"CurrentCapacity\"" "="] "\n"]
set level [string trim $lvl " \t\n"]
set changes 0
if {$last != $level} {
set v [expr abs(abs($last - $level)-1) * -10000]
set wouldBe [expr $delay + $v]
if {$v < 0 && $wouldBe > 0} {
set delay $wouldBe
set changes 1
}
if {$level <= $::min} {
set last $level
set msg "Batt low: $level"
puts -nonewline "\n"
puts -nonewline $msg
log $msg
enableWakeLock
exec shortcuts run mac-battery-low
continue
} elseif {$level >= $::max} {
set last $level
set msg "Batt high: $level"
puts -nonewline "\n"
puts -nonewline $msg
log $msg
exec shortcuts run mac-battery-high
disableWakeLock
continue
}
} else {
set canMaxBe [expr ($level*3000)]
if {$delay + 10000 <= $canMaxBe} {
incr delay 10000
set changes 1
}
}
if {$last != $level} {
set changes 1
}
set last $level
if {$changes == 1} {
puts -nonewline "\n"
puts -nonewline "Batt: $level"
puts -nonewline " ([expr $delay/1000] s)"
flush stdout
}
after $delay
}
Luego creé 2 atajos para "Atajos de Siri" y los nombré mac-battery-low
y mac-battery-high
. El primero encenderá la salida, el segundo lo apagará.
En la Terminal, simplemente ejecuto tclsh batt.tcl
(o hago chmod 755 batt.tcl
doble clic en el archivo) para comenzar a monitorear la batería. Ctrl
+ C
finalizará el seguimiento.
Editar
Remoto.
(Esto fue confuso ya que el script se actualizó y tiene una mejor solución).
editar2
Lo que he encontrado hasta ahora:
-> Por lo tanto, no es necesario verificar pmset -g assertions
las afirmaciones existentes.
Por lo tanto, permitimos que el sistema comience a dormir profundamente en cualquier momento si el cargador está apagado. Sin embargo, otros pueden evitar el sueño profundo y, por lo tanto, mantenernos en funcionamiento también. (comprobando periódicamente)
He actualizado el script anterior . En la primera ejecución, crea un archivo de configuración que le permite cambiar los valores para sesiones posteriores sin definir parámetros.
Quiero que esto esté basado en el sistema operativo, por lo que no necesito una conexión a Internet o un navegador abierto, etc. Solo algo que puede suceder en segundo plano.
La forma más fácil de hacerlo sería con una aplicación, pero aquí se explica cómo hacerlo solo con los comandos integrados del sistema operativo. Sé que desea que se base en eventos, pero no estoy seguro de cómo lograrlo, así que aquí hay una forma de verificar el nivel de la batería y luego hacer otra cosa si está por encima o por debajo de un umbral.
Puede considerar un launchd
proceso, esto es básicamente una tarea programada que se ejecuta cada x
minutos. A menudo son utilizados por usuarios avanzados, pero no son demasiado difíciles de configurar. Configura una tarea programada de lanzamiento con un archivo .plist que coloca en este directorio: Macintosh HD\Library\LaunchDaemons
y así es como estructura el archivo .plist;
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Debug</key>
<true/>
<key>ExitTimeOut</key>
<integer>120</integer>
<key>Label</key>
<string>com.me.BatteryInfo</string>
<key>ProgramArguments</key>
<array>
<string>/Users/yourusername/batt.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>1800</integer>
</dict>
</plist>
Si tuviera que guardar ese archivo como com.me.BatteryInfo
en la LaunchDaemons
carpeta mencionada anteriormente, crearía una tarea programada que se ejecuta cada 30 minutos. El número, 1800
directamente arriba, </dict>
es el tiempo en segundos de la frecuencia con la que desea que se ejecute la tarea. Donde dice <string>/Users/yourusername/batt.sh</string>
es donde especifica qué script se ejecuta según lo programado. Debes salir <string>
e </sting>
intacto.
La línea <string>com.me.BatteryInfo</string>
es el nombre único de la tarea programada. Si va a hacer más de uno, asegúrese de que cada .plist tenga un nombre único aquí.
Lo siguiente que debe hacer es cambiar la propiedad de .plist a root
. Esto es necesario como función de seguridad (supongo que para evitar que el software o los usuarios creen tareas maliciosas programadas). Para cambiar la propiedad del archivo, haga sudo chown root \Library\LaunchDaemons\yourtask.plist
(reemplace yourtask.plist con el nombre de archivo real del .plist que creó). Esta tarea le pedirá una contraseña.
Ahora necesita crear el script que se ejecutará periódicamente. Debe crear un archivo .sh (un script bash) para decirle a la computadora qué hacer. Para crear un archivo .sh, abra un editor de texto para programadores, como Sublime Text o Komodo Edit . NO use Text Edit, ya que a menudo agrega texto a sus archivos que interferiría con su script. Text Edit realmente no debería usarse para el código.
Cree un script (archivo .sh) con el siguiente código;
#!/bin/sh
percent=$(ioreg -l | awk '$3~/Capacity/{c[$3]=$5}END{OFMT="%.3f";max=c["\"MaxCapacity\""];print(max>0?100*c["\"CurrentCapacity\""]/max:"?")}')
if [ $percent > 95 ]
then
echo 'charged.'
fi
exit 0
Reemplace echo 'charged.'
con los comandos de terminal que le gustaría ejecutar cuando la batería esté cargada. open /Applications/Notes.app
abrirá la aplicación Notas; puede cambiar el directorio para abrir una aplicación diferente.
$percent > 95
Esto le dice a la siguiente línea que solo se ejecute cuando la batería esté más que 95
cargada. Puedes cambiar esto a lo que quieras. El nivel de la batería aquí a menudo será ligeramente diferente al que se muestra en la barra de menú en la parte superior. Si desea 'ejecutar cuando la batería esté completamente cargada', le recomiendo dejar esto como > 95 . Si desea que la tarea se ejecute cuando la batería esté por debajo del 20 %, por ejemplo, cámbiela a$percent < 20
NOTA: Debido a que esta es una tarea programada, su secuencia de comandos se ejecutará cada x
cierto número de minutos. Esto significa que si coloca open \Applications\Notes.app
dentro de su secuencia de comandos, la aplicación Notas se iniciará cada x
minutos (si su batería está cargada)
Esta tarea se ejecutará incluso si nadie ha iniciado sesión.
Sé que hiciste esta pregunta hace un tiempo, pero espero que esto ayude a alguien.
Power Manager no es gratuito, pero admite la activación de eventos en función de los niveles de la batería (interna o UPS). Los eventos pueden ejecutar scripts, iniciar aplicaciones o realizar tareas como apagar.
Power Manager se basa en eventos y no sondea los cambios de batería.
En cambio, Power Manager se conecta a la capa IOKit de OS X y espera actualizaciones del hardware. Los eventos se pueden activar cuando nadie ha iniciado sesión; no depende de un usuario activo.
Las tareas integradas del Asistente de programación se enfocan en el desempeño cuando la batería baja a un nivel particular, pero se pueden modificar para verificar si aumenta el porcentaje de batería o el tiempo restante.
Estas dos publicaciones hablan sobre las fuentes de energía UPS, pero se adaptan fácilmente a la batería interna de su MacBook:
Divulgación: Soy un ingeniero de software detrás de Power Manager.
Esto no es específico de Mac, pero Mozilla Aurora tiene una API integrada que contiene una variedad de funciones relacionadas con la batería. Uno puede detectar el estado de la batería (si se está cargando o no), cuánto tiempo más tardará la batería en descargarse/cargarse y su nivel. Hay un ejemplo simple de cómo agregar un EventListener para llamar a una función cuando el nivel de la batería está en un punto determinado.
malabarista defectuoso
Anticro