Скрипт для воспроизведения предупреждения, когда уровень заряда батареи ниже порога в MacOS - PullRequest
0 голосов
/ 01 января 2019

Я использую 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, но iOS остановил crontab.Затем я обнаружил, что мне нужно использовать launchd, который подробно описан ниже: https://alvinalexander.com/mac-os-x/mac-osx-startup-crontab-launchd-jobs

Сейчас он работает на моем MacBook Labtop, но могут быть и более эффективные решения.Поделитесь со мной, если у вас есть другие решения.Большое спасибо.

Ответы [ 2 ]

0 голосов
/ 02 января 2019

Я думаю, что ваш скрипт является хорошим сценарием сам по себе, но может оказаться довольно ресурсоемким при регулярном запуске, потому что он вызывает процесс оболочки плюс две программы для получения нужной вам информации.

В этом случае, я думаю, у AppleScript есть несколько преимуществ сценария оболочки, во многом благодаря osascript, единственной программе, которая должна выполняться для запуска AppleScript, и это можно сделать без создания оболочкиprocess.

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, вы будете предупрежденыуведомление в центре уведомлений и успокаивающие шотландские тона Мойры, которые дадут звуковое предупреждение о низком уровне заряда батареи.

Если уровень заряда батареи станет критически низким, вы получите всплывающее предупреждениечто вам придется физически уволить себя.

Скрипт также возвращает кучу другой информации о батарее, которую, вообще говоря, вы не увидите.Но, если сценарий исполняется списком launchd, возвращенная информация записывается в файл журнала, который вы можете просмотреть на досуге.

launchd

launchdобеспечивает хорошее, довольно экономичное средство выполнения сценариев через равные промежутки времени и является гораздо более предпочтительным, чем создание приложения Stay Open для опроса данных (это крайне неэффективно, но его использование вдругие сценарии).

Вы уже нашли хорошую ссылку, чтобы описать основы написания файла .plist и его сохранения, а затем вызвать (запустить) его.Я суммирую основные моменты здесь:

  1. Создайте .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.В этом случае я сохранил мой как local.battery.plist.Я также сохранил свой AppleScript по пути, который вы видите указанным в списке.В своих экспериментах я был весьма удивлен, что launchd не понравилось, если в пути были пробелы (даже если он был экранирован) или если я использовал тильду (~) в качестве сокращения для моего домашнего каталога.Поэтому я сохранил AppleScript как просто Battery.applescript и указал полный путь к месту его размещения.

    StartInterval - это место, где вы можете указать интервал (в секундах), с которым должен запускаться скрипт.Лично я думаю, что 60 секунд - это немного излишне, но я настроил это на тестирование.На практике я мог бы выбрать для него что-то вроде 600 (10 минут), но вы можете судить, что лучше для вас.

    В двух путях /tmp/ в конце записываются ошибки и возвращаемые значениясоответственно.Если вы измените путь к файлу журнала, не забудьте обновить свойство file в AppleScript.

  2. Сохраните или переместите plist в каталог ~/Library/LaunchAgents/.

  3. Загрузите его с помощью следующей команды оболочки из терминала:

    launchctl load ~/Library/LaunchAgents/local.battery.plist
    
  4. Если позднее вы внесете какие-либо изменения в .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 , который дает очень хороший, компактный и простой способ получения более существенной информации о батарее, т.е.процентный уровень и заряжается он или нет.Возможно, это может быть более подходящим решением AppleScripting, чем мой метод ObjC, который будет нести small накладные расходы, а также позволит сделать сценарий намного короче.

Пока я придерживаюсьс моим, потому что у меня, очевидно, есть проблемы со здоровьем батареи, и, вероятно, я должен решить эту проблему.

0 голосов
/ 01 января 2019

Я видел ваш вопрос и пытался что-то кодировать.

Вот AppleScript:

    on run
    set theBattString to (do shell script "pmset -g batt")
    -- the above will return something like...
    -- Now drawing from 'Battery Power' -InternalBattery-0  82%; discharging; 4:06 remaining

    set batteryLevel to splitText(theBattString, space)

    --I used this line under for counting the number of items in batteryLevel. 
    --Then I get the right item for the time remaining. 
    --It is a static value for me it was item 9.

    --set totalItembatLvl to length of batteryLevel 

    tell application "System Events"
    set remainingTime to item 9 of batteryLevel

    if remainingTime < "3:10" then                 

        display alert "low battery " & remainingTime & " before shut down."


        --batteryLevel & " " & remainingTime


    end if
    end tell
    end run

    on splitText(theText, theDelimiter)
      set AppleScript's text item delimiters to theDelimiter
      set theTextItems to every text item of theText
      set AppleScript's text item delimiters to ""
      return theTextItems
    end splitText

Вы можете сохранить его как простое приложение, и оно будет каждую минуту проверять уровень заряда батареи.

    on idle
    set theBattString to (do shell script "pmset -g batt")
    -- the above will return something like...
    -- Now drawing from 'Battery Power' -InternalBattery-0  82%; discharging; 4:06 remaining

    set batteryLevel to splitText(theBattString, space)

    --set totalItembatLvl to length of batteryLevel

    set remainingTime to item 9 of batteryLevel

    if remainingTime < "2:40" then
       display alert "low battery " & remainingTime & " before shut down."

       --batteryLevel & " " & remainingTime

    end if
    return 60
    end idle

on splitText(theText, theDelimiter)
    set AppleScript's text item delimiters to theDelimiter
    set theTextItems to every text item of theText
    set AppleScript's text item delimiters to ""
    return theTextItems
end splitText

Скажите, что вы думаете, и, возможно, другие могут улучшить этот ответ.

С уважением.

[РЕДАКТИРОВАТЬ]

Спасибо пользователю@ user3439894, который дает соответствующий код, который подходит для ваших нужд.

set batteryPercent to word 6 of paragraph 2 of (do shell script "pmset -g batt")

if batteryPercent < 40 then

    beep

    repeat 3 times

        say "Attention " & batteryPercent & "%" & " before shut down."

    end repeat

end if

Как и мой первый код, вы можете поместить его в простое приложение.

 on idle

    set batteryPercent to word 6 of paragraph 2 of (do shell script "pmset -g batt")

    if batteryPercent < 40 then



        repeat 3 times

            beep

            say "Attention " & batteryPercent & "%" & " of charge before shut down."

        end repeat

    end if

    return 60

end idle

С уважением

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...