Script to Play a Battery Charge Notification or Warning

Does it charge fast enough that it could possibly go from 89-91 inside 5 minutes? I doubt it, but worth considering.

Do you mean charge so quickly that it skips “90” altogether and doesn’t sound at all? Possibly.
If so, what’s the proper way to represent the range “89 to 91” in bash inside that statement?

$battery -ge 89 && $battery -le 91 will return true if the battery is at 89, 90, or 91. This also means you could conceivably get the alert three different times.

If you want to make damn sure it only “dings” one time within that range, you could use a boolean variable initialized to “false” and set it to true the first time it “dings” and back to false when the battery drops back below 89.

Depending on the phone’s charging rate, though, it may or may not be necessary.

1 Like

You should be careful about whether the cron job needs to run as root (preferably not) but if so, what directory it should go in and what permissions it should have.

Also, you don’t need bash in front of the name of a shell script.

1 Like

So, like this?
*/5 * * * * /home/purism/batwarn.sh
or maybe:
./batwarn.sh

Where should root ones go? (Although I don’t plan to run any, but just out of curiosity…)

For the command, yes, but you are missing the sixth field, which gives the user to run the command as.

If the script will run fine as purism then that’s what you should do.

I believe that you should always specify full paths for commands that aren’t in the standard path. You can override the definition of the standard path in the crontab file itself if you want to.

So, in summary, /etc/crontab would contain the following line:
*/5 * * * * purism /home/purism/batwarn.sh

You may, however, be using a private crontab file i.e. a user-specific crontab file, in which case
a) you don’t specify the user (the sixth field), and
b) I don’t know how it defaults PATH and hence it would in some sense be safer to specify a full path in the command. I think PATH always has the same default.

I don’t know about “should” but I would probably put it in root's home directory i.e. /root

2 Likes

Not with a cron job you can’t - because there is no shell state preserved between runs every X minutes.

Better to make it a service and then it can loop and sleep, and use boolean variables etc. If sticking with a cron job then state would need to go in a file e.g. in ~purism.

FWIW, what used to work under Amber doesn’t seem to be working under Byzantium i.e. a shell script that runs as a cron job that attempts to play a sound. In my case the cron job is not running as user purism but that did previously work.

The shell script works correctly if I create a Terminal from the phone GUI and then run the shell script (which is therefore running “interactively” as purism).

If I ssh in as the other user and run the script “interactively” then it executes without incurring any errors but just doesn’t play any sound! (Doing this works fine on Raspbian although the application there is completely different.)

I haven’t yet worked out whether this simply won’t work under Byzantium or it needs changes. Anyone got something like this working under Byzantium?

1 Like

Odd… I was already on byzantium when I created this script.

If I ssh in as purism (my only user), the command mplayer /home/purism/batwarn.ogg plays the warning on the L5.

My cron is:
*/5 * * * * ./batwarn.sh

And my currrent script is:

#!/bin/bash

# In order for cron to play sound files it needs to export an environment variable:
export XDG_RUNTIME_DIR="/run/user/1000"

state=$(upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep "state" | awk '{print $2}')
battery=$(upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep "percentage" | awk '{print $2}')
battery=${battery/\%/}

if [[ $state == discharging && $battery -le 40 ]]; then

    mplayer /home/purism/batalarm.ogg

fi

#    mplayer /home/purism/batalarm.ogg && espeak "charge battery"

#elif [[ $state == charging && $battery -eq 90 ]]; then

#    mplayer /home/purism/batalarm.ogg && espeak "90% charge"

It was working before (and recently), but now it seems to not be working.

EDIT: battery_BAT0 should be battery_max170xx_battery for the L5. (See my next comment.)

4 Likes

OK, thanks for the data point. I’m not playing using mplayer and I’m not playing a .ogg file - so those are some differences for me to explore. (I’m playing a .wav file.)

There are a lot of different environments though, separately from the above considerations
e.g. ssh in as purism (if allowed, not allowed on my phone)
ssh in as “another user”
(system or user) cron job as purism
(system or user) cron job as “another user”
service?
autostart?

The ssh was really just for testing. What I need is for it to work in some kind of environment like cron i.e. runs periodically in the background, makes a test of some kind, and conditionally outputs a sound file. (My application here was indeed a battery charge level warning but the scope for extending that to other things is obvious, if it worked at all.)

And, yeah, I’m not sure what would happen if the background script outputs a sound file while I am on the phone. Good problem to have? :wink:

I need to spend some time to work through the options and document the results systematically.

2 Likes

Oops… I see why mine isn’t working. Somehow in making copies across different devices, I ended up with “battery_BAT0” in the L5 script, when it should be battery_max170xx_battery, as in my OP.

I’m charging right now, but I’ll test it later to see if it’s working correctly.

3 Likes

@irvinewade, the script+cron is working fine now for me.

3 Likes

Yes, it is now working again for me.

  • I chose to change from running the script as a different user (let’s call it admin) to running the script as purism. It just seemed as if the former approach, which worked fine under amber, was likely to be more troublesome.
  • Running it as admin wasn’t working anyway because admin was not a member of the audio group. Easily fixed of course.
  • As you note above, I needed to define XDG_RUNTIME_DIR to run this successfully.

For the record, I am using the system crontab file whereas you appear to be using the user crontab file.

3 Likes

What would be the correct entry to run it as system?

1 Like

I believe that 3 changes would be needed

  1. It would go in a different file i.e. /etc/crontab for the system crontab file.
  2. Most importantly, there is an extra field in entries in the system crontab file. The extra field specifies what user the cron job runs under. The extra field becomes the sixth field i.e. immediately before the command to execute.
  3. It could be unsound to use a relative path in the command. I mean it might work or it might not - unless you can find appropriate documentation.

So in summary

*/5 * * * * purism /home/purism/batwarn.sh

Obviously, by using the system crontab file, it is far easier to change what user jobs run under - and you get a better overview of all the jobs that are scheduled. The downside of the system crontab file is that users can’t schedule their own jobs - but that is unlikely to be a problem on a device that has a single human user (like a phone).

2 Likes

I suppose it follows that a user cron job on a single-person-use, or rather single-user-use device isn’t a problem, either…?

1 Like

Yes, it’s not a problem to use a user cron job.

I think the downsides of the user cron job are that you “have to” use the crontab command to edit the user crontab file and that you end up with two files that together tell you about all the cron jobs (since by default a Linux system will have 4 cron jobs that “the system” puts in the system crontab file).

To make matters worse, 3 of those system cron jobs are by default deferred to anacron if it is installed. So that means that your cron jobs are spread over 3 files if you use user cron jobs. However it looks as if PureOS doesn’t install anacron by default.

2 Likes