bash - 在 MacOS 中,当电池电量低于阈值时播放警告的脚本

标签 bash macos scripting applescript battery

我正在使用 MacBook,但电池不可靠。我试图找到一个脚本命令,当电池电量低于阈值时,该命令将使笔记本电脑发出哔哔声。经过一些搜索和测试,我在下面找到了一个快速解决方案:

1)我首先创建一个名为 check_battery 的文件,内容如下:

ioreg -l | awk '$3~/Capacity/{c[$3]=$5}END{OFMT="%.3f";max=c["\"MaxCapacity\""]; bat= (max>0?100*c["\"CurrentCapacity\""]/max:"?"); printf("%d", bat)}'

2)然后我创建了以下文件:
\#!/bin/bash
sh check_battery>battery;
let t=60
read a < battery
if(( "$a" < "$t" ));
  then
  say "Battery level is lower than 60%!";
  say "BEAP BEAP"
fi;

3)最后,我尝试将其添加到我的 crontab 作业中,但 crontab 已被 iOS 停止。然后我发现我必须使用launchd,具体如下:
https://alvinalexander.com/mac-os-x/mac-osx-startup-crontab-launchd-jobs

它现在在我的 MacBook 实验室中工作,但可能有更好的解决方案。如果您有其他解决方案,请与我分享。非常感谢。

最佳答案

我认为您的脚本本身就是一个很好的脚本,但在定期运行时最终可能会占用大量资源,因为它会调用一个 shell 进程和两个程序来获取您想要的信息。

在这种情况下,我认为 AppleScript 具有 shell 脚本的几个优点,这主要归功于 osascript ,这是唯一一个需要执行才能运行 AppleScript 的程序,它可以在不创建 shell 进程的情况下执行此操作。

用于检索电池信息的 AppleScript

这是一个这样的脚本,它可以检索有关计算机电池的信息,并在适当的时候发出警告:

property threshold : 20 -- The level below which the script issues warnings
property verbose : false -- Report current battery level on every run
property file : "/tmp/battery.log" -- The path to the log file (from plist)


set eof of my file to 0

tell the battery()
    set warning_level to the warningLevel()
    if the warning_level = 1 then return check()
    warn about (warning_level - 1) * 5 with alert
end tell

# warn
#   Sends out a visible and audible warning with information about the
#   remaining charge (+level) on the battery.  Invoke without alert to have
#   the +level reported in the notification centre as a percentage.  Invoke 
#   with alert to have the +level reported in a pop-up alert dialog as an
#   estimation of the remaining battery time (in minutes), and which must be
#   dismissed by the user.
to warn about level without alert
    if not alert then display notification ¬
        ["Current battery level: ", level, "%"] as text ¬
        with title ["⚠️ Battery Warning"] sound name "Basso"

    say "Warning: battery low" using "Moira" pitch 127 ¬
        speaking rate 180 without waiting until completion

    if alert then display alert ["Warning: battery level is very low"] ¬
        message ["Estimated time remaining: " & level & " minutes"] ¬
        as critical giving up after 0
end warn

# battery()
#   Contains a script object that defines a number of convenience handlers that
#   retrieve information about the on-board power source
on battery()
    script
        use framework "IOKit"
        use scripting additions
        property warninglevels : ["None", "Early", "Final"]

        on warningLevel() -- A ten-minute warning indicator
            IOPSGetBatteryWarningLevel() of the current application
        end warningLevel

        on info()
            IOPSCopyPowerSourcesInfo() of the current application ¬
                as record
        end info

        to check()
            copy [it, |current capacity|, |is charging|] of ¬
                info() to [ps_info, percentage, charging]

            if the percentage ≤ threshold ¬
                and it is not charging ¬
                then warn about percentage ¬
                without alert

            if verbose then return display notification [¬
                "Percentage: ", percentage, linefeed, ¬
                "Charging: ", charging] as text ¬
                with title ["🔋 Battery Information"]

            ["Script last run on ", current date, linefeed, ¬
                linefeed, __string(ps_info), linefeed] as text
        end check
    end script
end battery

# __string()
#   A that will return an AppleScript record as a formatted string, modified
#   specifically for use in this script, therefore may not port very well to
#   handle other records from other scripts
to __string(obj)
    if class of obj = text then return obj

    try
        set E to {_:obj} as text
    on error E
        my tid:{null, "Can’t make {_:", ¬
            "} into type text.", ¬
            "{", "}", "|"}
        set E to E's text items as text
        my tid:{linefeed, ", "}
        set E to E's text items as text
    end try
end __string

# tid:
#   Set the text item delimiters
on tid:(d as list)
    local d

    if d = {} or d = {0} then set d to ""
    set my text item delimiters to d
end tid:

它最显着地检索电池剩余电量的当前百分比以及电池当前是否正在充电。

您可以根据自己的喜好安全地更改脚本顶部的三个属性。在 verbose模式,每次运行脚本时都会报告电池百分比和充电状态。如果您按分钟运行脚本,这可能会令人恼火,因此将其设置为 false默认情况下。

但是,当电池电量低于 threshold 时,您将收到通知中心的通知,以及 Moira 舒缓的苏格兰语气,它会发出声音警告,提示击球手电量不足。

如果电池电量严重不足,您会收到一个弹出式警报,提示您必须亲自离开。

该脚本还会返回一堆有关电池的其他信息,一般来说,您不会看到这些信息。但是,如果脚本被 launchd 执行plist,返回的信息记录在日志文件中,您可以在闲暇时检查。
launchdlaunchd提供了一种很好的、​​具有成本效益的定期运行脚本的方法,并且比创建 Stay Open 应用程序来轮询数据更可取(这是非常低效的,但在其他场景中也有用途)。

您已经找到了一个很好的链接来描述有关编写 .plist 的基础知识。文件以及如何保存它,然后调用(启动)它。我将在这里总结要点:
  • 创建一个 .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>Disabled</key>
            <false/>
            <key>Label</key>
            <string>local.battery</string>
            <key>ProgramArguments</key>
            <array>
                    <string>/usr/bin/osascript</string>
                    <string>/Users/CK/Documents/Scripts/AppleScript/scripts/Battery.applescript</string>
            </array>
            <key>RunAtLoad</key>
            <true/>
            <key>StartInterval</key>
            <integer>60</integer>
            <key>StandardErrorPath</key>
            <string>/tmp/battery.err</string>
            <key>StandardOutPath</key>
            <string>/tmp/battery.log</string>
    </dict>
    </plist>
    

    使用与 <string> 匹配的文件名保存它Label下的条目 key 。在这种情况下,我将我的保存为 local.battery.plist .我还在 plist 中指定的路径中保存了我的 AppleScript。在我的实验中,我很惊讶 launchd如果路径中有任何空格(即使已转义),或者如果我使用波浪号( ~ )作为主目录的简写,我就不喜欢它。因此,我将 AppleScript 保存为简单的 Battery.applescript并提供了我放置它的完整路径。
    StartInterval您可以在此处指定脚本运行的间隔(以秒为单位)。就个人而言,我认为 60 秒有点矫枉过正,但我​​将其设置为用于测试。在实践中,我可能会选择将其设置为 600(10 分钟)之类的值,但您可以判断什么最适合您。

    两人/tmp/最后的路径分别是写入错误和返回值的地方。如果更改日志文件的路径,请不要忘记更新 file AppleScript 中的属性。
  • 将 plist 保存或移动到目录 ~/Library/LaunchAgents/ .
  • 从终端使用以下 shell 命令加载它:
    launchctl load ~/Library/LaunchAgents/local.battery.plist
    
  • 如果稍后您对 .plist 进行了任何更改或 .applescript ,记得先卸载再用launchctl重新加载:
    launchctl unload ~/Library/LaunchAgents/local.battery.plist
    launchctl load ~/Library/LaunchAgents/local.battery.plist
    

  • 成功加载 .plist 后进入 launchd ,它应该立即运行 AppleScript 并将返回的数据写入日志文件。这是我的 /tmp/battery.log 的输出文件:
    Script last run on Tuesday, 1 January 2019 at 22:01:52
    
    is present:true
    is charged:true
    power source state:"AC Power"
    Current:0
    max capacity:100
    DesignCycleCount:1000
    current capacity:100
    name:"InternalBattery-0"
    battery provides time remaining:true
    is charging:false
    hardware serial number:"D8663230496GLLHBJ"
    transport type:"Internal"
    time to empty:0
    power source id:4391011
    Type:"InternalBattery"
    BatteryHealth:"Check Battery"
    time to full charge:0
    

    闭幕式

    第一次电池信息非常有趣,但对于大多数用例来说可能是多余的。 (也就是说,我已经 只有 注意到有人建议我在 "Check Battery"BatteryHealth ,所以我现在很高兴我提取了额外的数据)。

    无论如何,如果额外的数据不是你认为自己需要的东西,我已经看到了 user3439894 留下的评论。这提供了一种非常好的、紧凑的和简单的方法来检索有关电池的更显着信息,即它的百分比水平以及它是否正在充电。这可以说是比我的 ObjC 方法更合适的 AppleScripting 解决方案,它会带来很小的开销,而且可以制作更短的脚本。

    现在,我坚持我的,因为我显然有电池健康问题,可能应该解决这个问题。

    关于bash - 在 MacOS 中,当电池电量低于阈值时播放警告的脚本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53997451/

    相关文章:

    regex - 将匹配 YYMMDD 但不匹配更长数字的 bash 正则表达式

    swift - 如何从 cocoa 应用程序运行终端命令?

    JSON 数据不显示在 NSTableView 中

    ios - 如何从该 LAN 上的 IP 地址解析我 LAN 中设备的主机名?

    javascript - CSS 类未在节点中应用

    具有字段值条件的 Linux cut 命令

    java - bashrc 不识别 java 主目录

    linux - 如何在 Bash/Ubuntu 12.04 中正确编写这个算术表达式?

    bash - 在不退出终端的情况下保留源代码的 shell 脚本

    linux - sed 提取给定日期之间的日志