14 votes

Événement basé sur le niveau de charge de la batterie

Je n'ai encore rien trouvé, alors j'espérais que quelqu'un ici aurait une idée.

Je veux lancer un événement basé sur le fait que la batterie d'un ordinateur portable Apple atteint un certain niveau de charge, ou lorsque la batterie est complètement chargée.

Je sais que je peux faire en sorte que quelque chose s'exécute périodiquement, vérifier le niveau de la batterie et décider de ce qu'il convient de faire, mais je préfère, si possible, que l'événement soit piloté.

8voto

Joseph Points 1141

Je veux que ce soit basé sur le système d'exploitation, donc je n'ai pas besoin d'une connexion Internet ou d'un navigateur ouvert, etc. Juste quelque chose qui peut se produire en arrière-plan

La façon la plus simple de le faire serait avec une application, mais voici comment le faire avec les commandes intégrées du système d'exploitation uniquement. Je sais que vous voulez qu'elle soit pilotée par des événements, mais je ne suis pas sûr de savoir comment y parvenir. Voici donc une façon de vérifier le niveau de la batterie, puis de faire autre chose s'il est supérieur ou inférieur à un seuil.

Vous pouvez envisager un launchd Il s'agit essentiellement d'une tâche planifiée qui s'exécute à chaque x minutes. Ils sont souvent utilisés par des utilisateurs avancés, mais ne sont pas trop difficiles à mettre en place. Vous configurez une tâche planifiée launchd avec un fichier .plist que vous placez dans ce répertoire : Macintosh HD\Library\LaunchDaemons et c'est ainsi que vous structurez le fichier .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 vous enregistrez ce fichier en tant que com.me.BatteryInfo dans le LaunchDaemons Le dossier mentionné ci-dessus crée une tâche planifiée qui s'exécute toutes les 30 minutes. Le numéro, 1800 directement au-dessus </dict> est la durée en secondes de la fréquence à laquelle vous souhaitez que la tâche soit exécutée. Où il est écrit <string>/Users/yourusername/batt.sh</string> est l'endroit où vous spécifiez quel script s'exécute sur le planning. Vous devez laisser <string> et </sting> intact.

La ligne <string>com.me.BatteryInfo</string> est le nom unique de la tâche planifiée. Si vous devez en créer plusieurs, assurez-vous que chaque fichier .plist porte un nom unique.

La prochaine chose que vous devez faire est de changer la propriété du .plist en root . Ceci est nécessaire pour des raisons de sécurité (pour empêcher les logiciels/utilisateurs de créer des tâches malveillantes programmées, je suppose). Pour changer la propriété du fichier, faites sudo chown root \Library\LaunchDaemons\yourtask.plist (remplacez yourtask.plist par le nom de fichier réel du .plist que vous avez créé). Cette tâche vous demandera un mot de passe.

Maintenant vous devez créer le script qui sera exécuté périodiquement. Vous devez créer un fichier .sh (un script bash) pour indiquer à l'ordinateur ce qu'il doit faire. Pour créer un fichier .sh, ouvrez un éditeur de texte pour programmeurs, tel que Texte sublime o Komodo Edit . N'utilisez PAS Text Edit, car il ajoute souvent du texte à vos fichiers qui interférerait avec votre script. L'édition de texte ne devrait pas vraiment être utilisée pour le code.

Faites un script (fichier .sh) avec le code suivant ;

#!/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

Remplacer echo 'charged.' avec la ou les commandes du terminal que vous souhaitez exécuter lorsque la batterie est chargée. open /Applications/Notes.app ouvrira l'application Notes ; vous pouvez changer le répertoire pour ouvrir une autre application.

$percent > 95 Cela indique à la ligne suivante de ne s'exécuter que lorsque la batterie est supérieure à 95 chargé. Vous pouvez modifier cette valeur comme vous le souhaitez. Le niveau de la batterie est souvent légèrement différent de ce qui est affiché dans la barre de menu en haut de l'écran. Si vous souhaitez que l'application fonctionne lorsque la batterie est entièrement chargée, je vous recommande de laisser la valeur > 95. . Si vous voulez que la tâche s'exécute lorsque votre batterie passe en dessous de 20 % par exemple, changez-le en $percent < 20

NOTE : Comme il s'agit d'une tâche planifiée, votre script sera exécuté chaque x nombre de minutes. Cela signifie que si vous mettez open \Applications\Notes.app à l'intérieur de votre script, l'application Notes démarrera chaque x minutes (si votre batterie est chargée)

Cette tâche sera exécutée même si personne n'est connecté.

Je sais que vous avez posé cette question il y a un certain temps, mais j'espère que cela pourra aider quelqu'un.

5voto

Graham Miln Points 39606

Gestionnaire d'énergie n'est pas gratuit mais permet de déclencher des événements en fonction du niveau des batteries (internes ou UPS). Les événements peuvent exécuter des scripts, lancer des applications ou effectuer des tâches telles que l'arrêt.

Power Manager est piloté par les événements et n'interroge pas les changements de batterie.

Au lieu de cela, Power Manager s'accroche à la couche IOKit d'OS X et attend les mises à jour du matériel. Des événements peuvent être déclenchés lorsque personne n'est connecté ; il ne dépend pas d'un utilisateur actif.

Power Manager - Run a script on battery remaining

Les tâches intégrées de l'assistant de programmation sont exécutées lorsque la batterie atteint un niveau particulier, mais elles peuvent être modifiées pour vérifier les augmentations du pourcentage de la batterie ou du temps restant.

Ces deux billets parlent des sources d'alimentation des onduleurs, mais ils sont facilement adaptables à la batterie interne de votre MacBook :

Divulgation : Je suis un ingénieur logiciel derrière Power Manager.

2voto

parkr Points 1140

Ce n'est pas spécifique au Mac, mais Mozilla Aurora a une API intégrée qui contient une variété de fonctions liées à la batterie. On peut détecter l'état de la batterie (si elle est en charge ou non), combien de temps il faudra encore à la batterie pour se décharger/se charger, et son niveau. Voici un exemple simple de la façon d'ajouter un EventListener pour appeler une fonction lorsque le niveau de la batterie atteint un certain point.

2voto

Anticro Points 136

Bon, cette question est ancienne mais j'ai rencontré une situation similaire et j'ai voulu lancer un raccourci (avec "Siri Shortcuts") sur MacOS 12 sur certains niveaux de batterie.

Au lieu d'un service d'arrière-plan, j'ai décidé qu'un script fonctionnerait mieux pour moi puisqu'il devrait allumer et éteindre ma prise HomeKit à laquelle le chargeur est connecté. (Mais seulement pendant que le MacBook est en train de transcoder un film).

A partir de la réponse de Joseph, j'ai pris les morceaux qui fonctionnent encore et j'ai créé un Tcl script qui vérifie le niveau de la batterie toutes les minutes.

J'ai créé un fichier nommé batt.tcl avec le contenu suivant :

#!/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

}

Puis j'ai créé 2 raccourcis pour "Siri Shortcuts" et les ai nommés mac-battery-low et mac-battery-high . Le premier allume la prise, le second l'éteint.

Sur le Terminal, je lance simplement tclsh batt.tcl (ou chmod 755 batt.tcl et double-cliquez sur le fichier) pour commencer à surveiller la batterie. Ctrl + C mettra fin à la surveillance.

Modifier

Supprimé.

(Cela portait à confusion puisque le script a été mis à jour et présente une meilleure solution).

Edit2

Ce que j'ai trouvé jusqu'à présent :

  1. Le processus de "caféination" maintient le système en état de marche.
  2. Nous devrions seulement caféiner le système pendant la charge, car il y a aussi d'autres processus qui caféinent pendant que l'utilisateur est actif.

-> Il n'y a donc pas besoin de vérifier pmset -g assertions pour les assertions existantes.

  1. Nous devons simplement créer une assertion propre qui maintient le Mac allumé pendant la charge. Lorsque nous avons atteint le niveau de batterie souhaité, nous déclenchons notre événement pour supprimer l'assertion. Tout processus de caféination peut être encore en cours d'exécution et maintenir le système allumé. Ou bien il est déjà terminé - ce qui permet au Mac de se mettre en veille immédiatement.

Nous permettons donc au système de se mettre en sommeil profond à tout moment si le chargeur est éteint. Cependant, d'autres personnes pourraient empêcher le sommeil profond et ainsi nous permettre de continuer à fonctionner. (vérification périodique)

J'ai mis à jour le script ci-dessus. . Lors de la première exécution, il crée un fichier de paramètres qui vous permet de modifier les valeurs pour les sessions ultérieures sans définir de paramètres.

LesApples.com

LesApples est une communauté de Apple où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres utilisateurs d'appareils Apple, poser vos propres questions ou résoudre celles des autres.

Powered by:

X