|
|||||||
![]() |
|
|
Thread Tools | Search this Thread | Display Modes |
|
|
#1 |
|
Bash script to warn user when charge drops below a specified level not working
Code:
#!/bin/bash
#
# The computer tells the user to plug them in and shows a Growl notification every minute.
#
# Setup:
# 1. Install growlnotify
# 2. Adjust threshold in line 20 (here 656mAh)
# 3. Create line in crontab like this:
# * * * * * /path/to/script/battery_low.sh
#Name of the user.
name="Habib"
#Level of charge in % to warn the user at.
warnat="101"
#Is the computer plugged in?
pluggedin=`/usr/sbin/system_profiler SPPowerDataType | grep "Connected:"`
#Is the computer charging?
charging=`/usr/sbin/system_profiler SPPowerDataType | grep "Charging:"`
#Is the computer fully charged?
charged=`/usr/sbin/system_profiler SPPowerDataType | grep "Fully Charged:"`
#If the computer is plugged in and charging, do nothing.
if [["$pluggedin" == *Yes* && "$charging" == *Yes*]]
then
exit
#If the computer is plugged in and not fully charged, but not charging, tell the user.
else if [["$pluggedin" == *Yes* && "$charging" == *No* && "$charged" == *No*]]
then
say "Something is wrong. Your computer is plugged in and not fully charged, but it's not charging."
else
#Charge remaining in mAh.
rem=`/usr/sbin/system_profiler SPPowerDataType | grep -i "Charge remaining" | sed 's/[^0-9]//g'`
#Current battery capacity in mAh.
cap=`/usr/sbin/system_profiler SPPowerDataType | grep -i "Full Charge Capacity" | sed 's/[^0-9]//g'`
#Charge remaining in percent. -l flag makes result floating point.
remperc=`echo "$rem/$cap*100" | bc -l`
#This turns the value of remperc into an integer, so users don't hear a number with loads of digits after it.
remperc=`echo "$remperc" | awk '{printf("%d\n",$1 + 0.5)}'`
echo "$remperc"
if [ "$remperc" -lt "$warnat" ]
then
#/usr/local/bin/growlnotify -n batteryAlert -p High -m "Battery level low… ($remperc%)"
say "$name, plug me in! I'm low on juice. I only have $remperc percent left."
fi
fi
fi
I also get this output at runtime: Code:
/Users/Habib/Expanded/battery_low_vague.sh: line 24: [[ Connected: Yes: command not found /Users/Habib/Expanded/battery_low_vague.sh: line 28: [[ Connected: Yes: command not found 100 |
|
|
|
0
|
|
|
#2 |
|
|
0
|
|
|
#3 |
|
|
0
|
|
|
#4 | |
|
Quote:
However, I am now having another problem. Launchd is giving me a massive headache. I just want to try run this script every minute, but it won't do it. I've tried running the script manually to test it and everything works as it should. Plus, I've piped the output of launchctl list to a text file and my plist is there. But it won't launch the script. I'll show you it when I get home today. |
||
|
|
0
|
|
|
#5 |
|
Can you run it under crontab?
|
|
|
|
0
|
|
|
#6 |
|
I haven't tried, but I want that to be my last resort, since launchd has superseded crontab and I prefer to do things the default way.
Edit: I'm new to all of this anyway. I use bash occasionally, but this is probably only the 2nd/3rd time shell scripting. I also am completely new to both launchd and cron. I've heard of them, but I've never used them for my own projects. |
|
|
|
0
|
|
|
#7 | |
|
Quote:
Post the complete actual launchd plist. Identify exactly where the launchd plist is located. If it's in /Library (the one at the root of your hard drive, not your personal ~/Library), then it needs to have root ownership. |
||
|
|
0
|
|
|
#8 |
|
OS X 10.7.3, second latest EFI update, MacBook Air Mid 2011, 13" 1.7 GHz i5.
This is just the current one. I've tried all sorts of combinations, including without the nice key (in fact, that's only there since I made it using Loginox and I saw I could change the nice value. None of the others had that), using Program and ProgramArgument, with PrArg Str1 as the script and the second string as start, with the second string as run, etc. This is just the latest attempt. Code:
<?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>Label</key> <string>com.Habib.batteryAlert</string> <key>Nice</key> <integer>-15</integer> <key>ProgramArguments</key> <array> <string>/bin/sh</string> <string>/etc/batteryalert/batteryAlert.sh</string> </array> <key>RunAtLoad</key> <true/> <key>StartInterval</key> <integer>60</integer> </dict> </plist> Done that already, I've set ownership to root and permissions to 644. I've also tried with ownership root and not changing permissions. Still doesn't work. |
|
|
|
0
|
|
|
#9 | |
|
Quote:
Code:
RunAtLoad <boolean>
This optional key is used to control whether your job is launched once at
the time the job is loaded. The default is false. [emphasis added]
Also, your designated shell (/bin/sh) doesn't match the one in the first line of the shell script. I'm not saying this is the cause, just that it's an inconsistency. Once you put the plist in place, did you use 'sudo launchctl' to actually start it? Or did you restart the computer? Because simply putting a plist in place doesn't start the job. If you still can't make it work, isolate the problem. Make a launchd plist that launches the 'say' program every 60 secs and has it say a constant string. Now you don't have to care about your battery-checking shell script, just the launchd plist. Finally, consider putting it in your ~/Library/LaunchAgents folder for testing. |
||
|
|
1
|
|
|
#10 | ||
|
Yes, I was told this would make the script run when the plist is loaded, not just every * seconds. I didn't know it would mean only once. I'm not even sure the man page is saying that. It says once at startup, but subsequent times every 60 seconds should still work, I'm sure. Even so, it should at least warn me once, right? If I boot with required battery level, it should still warn me once, just not every 60 seconds.
Quote:
Quote:
Gonna try this next. |
|||
|
|
0
|
|
|
#11 | |
|
Quote:
Thanks for helping me out. Everything is fine now. |
||
|
|
0
|
|
|
#12 | ||
|
Quote:
Simple logic suggests a simple strategy: try changing it, see what happens. ---------- Quote:
|
|||
|
|
0
|
|
|
#13 |
|
Yes, when it wasn't working, I piped launchctl list to a file and the plist was there, it just wasn't working. I wouldn't know how to check if it was disabled.
|
|
|
|
0
|
|
|
#14 | |
|
Quote:
Something else: launchd reads a plist once. If you edit the file after the job is loaded, launchd won't see the edits. This is one reason there are launchctl cmds for load and unload. |
||
|
|
1
|
|
|
#15 | |
|
Quote:
|
||
|
|
0
|
|
|
#16 | |
|
Quote:
|
||
|
|
0
|
|
|
#17 |
|
Hope you are aware of the difference between agents and daemons and the different privileges and scopes that are available and that you have picked the appropriate one. It's hard to get right, you could use something like Lingon to aid you. My suggestion was based upon that you said this was your 3rd shell script ever and the KISS principle.
|
|
|
|
1
|
|
|
#18 | |
|
Quote:
I placed it into the root Daemons folder since I want to be warned of low battery, even if I'm not logged in. |
||
|
|
0
|
|
|
#19 | ||
|
Quote:
You really need to read TN2083: https://developer.apple.com/library/...hnotes/tn2083/ In fact, you should probably bookmark it and refer to it whenever you think of writing a launchd daemon or agent. Quote:
All forms of user interaction, including sounds and speech synth, are severely restricted in a daemon. So much so you may as well assume there's no user interaction (either input or output) at all. Plus there's the whole "Whose security context is this anyway?" problem (i.e. who owns the screen interface; see TN2083). Unless there's a specific reason that a launch agent is incapable of solving the problem, then always using a launch agent is a much better default. You should be able to fill in the blank "I absolutely can't use a launch agent because ____", and back it up with citable evidence. If that seems extreme, consider it saving yourself from daemon-induced grief. Launch agents are allowed user interaction (though still limited). Rather than outline what's allowed and what's not, I recommend a thorough reading of TN2083. |
|||
|
|
1
|
|
|
#20 | |||
|
Quote:
Quote:
Quote:
Based on the TN, I placed it into LaunchAgents in the root. Here's the new version which will check the short name of the user to make the app portable: Code:
#!/bin/bash
#Name of the user.
name=`whoami`
#Level of charge in % to warn the user at.
warnat="11"
#Is the computer plugged in?
pluggedin=`/usr/sbin/system_profiler SPPowerDataType | grep "Connected:"`
#Is the computer charging?
charging=`/usr/sbin/system_profiler SPPowerDataType | grep "Charging:"`
#Is the computer fully charged?
charged=`/usr/sbin/system_profiler SPPowerDataType | grep "Fully Charged:"`
#If the computer is plugged in and charging, do nothing.
if [[ "$pluggedin" == *Yes* && "$charging" == *Yes* ]]
then
exit
#If the computer is plugged in and not fully charged, but not charging, tell the user.
else if [[ "$pluggedin" == *Yes* && "$charging" == *No* && "$charged" == *No* ]]
then
growlnotify -m "Your battery is plugged in and not fully charged, but it's not charging." --name "Battery Alert" --title Something wrong! --image /etc/batteryalert/batteryAlert.icns --sticky --priority High
say -v Samantha "Something is wrong. Your computer is plugged in and not fully charged, but it's not charging."
else
#Charge remaining in mAh.
rem=`/usr/sbin/system_profiler SPPowerDataType | grep -i "Charge remaining" | sed 's/[^0-9]//g'`
#Current battery capacity in mAh.
cap=`/usr/sbin/system_profiler SPPowerDataType | grep -i "Full Charge Capacity" | sed 's/[^0-9]//g'`
#Charge remaining in percent. -l flag makes result floating point.
remperc=`echo "$rem/$cap*100" | bc -l`
#This turns the value of remperc into an integer, so users don't hear a number with loads of digits after it.
remperc=`echo "$remperc" | awk '{printf("%d\n",$1 + 0.5)}'`
if [ "$remperc" -lt "$warnat" ]
then
growlnotify -m "Plug in an AC adapter now to avoid the risk of losing your work… ($remperc%)" --name "Battery Alert" --title Battery Low! --image /etc/batteryalert/batteryAlert.icns --sticky --priority High
say -v Samantha "$name, plug me in! I'm low on juice. I only have $remperc percent left."
fi
fi
fi
|
||||
|
|
0
|
|
|
#21 | |
|
Quote:
Working with daemons in the past, I've seen odd race conditions, where something didn't work simply because it happened to execute before some other daemon had a chance to, so the thing I wanted to use (network access, IIRC) failed intermittently. Moving it to be a launch agent completely solved the race condition. |
||
|
|
0
|
|
|
#22 |
|
I assume this isn't working because there a number errors in the script. Adding some echo commands is a good way to test, and/or testing out specific lines directly in terminal, usually with echo or piping into more.
Your if statements will not evaluate as you expect for a few reasons. I would probably do something like this: Code:
sysprofile_stuff=$(system_profiler SPPowerDataType)
pluggedin=$(echo "$sysprofile_stuff"|grep Connected|awk '{print $NF}')
charging=$(echo "$sysprofile_stuff"|grep Charging|head -n1|awk '{print $NF}')
charged=$(echo "$sysprofile_stuff"|grep Charged|awk '{print $NF}')
# and so on for other variables
# And as an example of why you should test your code, I get two matches
# for "Charging" - that kind of thing will bork your script if you don't know
# about it and plan for it.
Code:
if [[ "$pluggedin" == "Yes" && "$charging" == "Yes" ]] # you could also use awk here and not change your variables, # but this more efficient Code:
remperc=$(echo "$rem"/"$cap"*100 | bc -l) remperc=$(echo "$remperc" |cut -d'.' -f1) # or use `` to invoke subshells if you prefer, doesn't matter # and.. these variables both have the same name, so what is # the point of setting this to float and then back to a whole number, # which is what your awk command was doing, BTW |
|
|
|
0
|
|
|
#23 | |
|
Quote:
I've tested the script and it works perfectly. I don't have any issues on my side. It's more the launchd stuff that gives headaches. However, I now have a new issue. I'm trying to make an installer package to make it easy for other users to install it, but now it's just stopped working. I removed my one and used the installer to test if it works, but it just stops. When I check launchctl list and pipe it to a file, I search for my plist, but it isn't there. What the? I made sure all permissions were correct and placed it into /Library/LaunchAgents. I even made the installer require a restart. But no, it just won't show up. Also, I have tried adding scripts to load the plist after installation, but that doesn't work, so I just went with restarting. (I have also tried adding preupgrade and postupgrade scripts to unload it first, if it's already installed, then load the new one, but I can't even get it to work with a restart, so I don't want to go here yet.) I will attach the Installer document, so if you have PackageMaker, you can see if anything's wrong. I will also attach the package itself, so Pacifist users can also see. Sorry to bother you chown, I really didn't want to after you've helped so much already, but I've been trying to fix this for ages and it just won't work. Last edited by phySi0; Mar 11, 2012 at 05:48 AM. |
||
|
|
0
|
|
|
#24 |
|
Disregard!
Disregard. It started working after another restart, which I did for a completely unrelated reason, but meh… I'm going to need to do some more testing.
|
|
|
|
0
|
![]() |
|
| Tags |
| bash, battery, notification, script, shell |
«
Previous Thread
|
Next Thread
»
| Thread Tools | Search this Thread |
| Display Modes | |
|
|
Similar Threads
|
||||
| thread | Thread Starter | Forum | Replies | Last Post |
| Resolved: YouTube not working on Safari? | deannnnn | Mac OS X | 38 | Apr 2, 2013 06:44 PM |
| Java Applet not working on Lion | jake4ever | Mac OS X 10.7 Lion | 19 | Feb 1, 2013 09:44 AM |
| iPhone 4 ringer not working | Causality | iPhone Tips, Help and Troubleshooting | 3 | Oct 20, 2012 01:07 AM |
| Battery charging for MacBook Pro sometimes does not work | horace528 | MacBook Pro | 2 | Jan 9, 2012 07:08 AM |
| Youtube not working in Safari? | Hyde244 | Mac Applications and Mac App Store | 12 | Nov 16, 2011 11:12 PM |
All times are GMT -5. The time now is 03:03 AM.








Linear Mode

