Cronjob your New Year's resolutions
Dan Willoughby・ Dec 31, 2019・6 min read
My problem with resolutions
I've always set New Year's resolutions, but then immediately forgot about them within a week or two... Some of my resolutions are normally short term such as read 1 book (yes, that really is one I set in 2018, and didn't achieve it, haha) while others are more long term like workout 3 times a week. The main problem I have had is forgetting I had set these resolutions. I would remember for the first month or so, then I would slip right back into my old routine of not doing them.
This year I decided I'd write some small shell scripts to help myself remember my resolutions, track my progress, and send reminders.
My New Year's resolutions
There are many ways to separate or categorize resolutions, but I decided to focus on 3 main areas to automate with my cronjobs. The first two categories repeat at different intervals, where the third category only needs to be completed once.
- Eat healthy each meal
- Exercise 3 times a week
- Floss teeth daily
Repeating Maintenance (bi-monthly, semi-annual, etc)
- Change house air filter
- Change car oil
- Clean out fridge
Improvement goals (complete once)
- Read 1 book
- Fix light switch
To ensure better success this year, I plan to do at least three things differently than I have in the past. The first thing is to send myself reminders throughout the entire year. That way I can't simply forget about it. Second I want to track my excuses for why I didn't complete something. Finally, I want to have someone else be able to observe my progress.
Sending reminders with Pushback
I had made a simple push notification service called Pushback, which focused on turning shell scripts or simple programs into mobile apps. Pushback works in a similar way to a slack apps, allowing messages to be sent via an API. Once the message is sent, I can use the buttons on the push notifications to check off items. Pushback also has message history so I can go back and look at what excuses I've made.
Track my excuses
To better motivate myself this year, I decided I would track when I complete a task/goal, but I also want to track all the excuses I can come up with. I figure that way, when I look back, I can see a trend for why I'm not accomplishing certain things and make adjustments.
I have tried using several habit trackers and goal trackers throughout the years. I even made a habit tracker myself called Goalie. It worked for awhile, but the common trend among all of these was I couldn't track all different kinds of goals with them. I either wanted them to remind me about something daily or I'd want a reminder once a month. Sometimes I'd want exponential reminders if a task is needed to be completed within a certain time period.
The other problem I ran into, was that I had little accountability. If I missed a day, nothing would happen. I got into the habit of ignoring the notifications to the point where I stopped looking at them completely.
Share with others
I plan to use Pushback's channel sharing ability and invite a few others to view some of my resolutions, that way I can be a bit more motivated. It's not the ideal way to do it, but I think it will work. If I find something I think would be better, I might make another app that focuses on that.
Setting things up
Cronjobs are an excellent way to automate tasks that occur regularly. I've always thought the cronjob syntax was the most flexible way to specify exactly when you want an event to occur. Even though the syntax has a slight learning curve, I have found there are plenty of resources (googling it) that can help get a cronjob to run when I want it to.
For the daily habits, I just want a reminder each day. I made a simple bash script called habits.sh, that takes the habit title as the first argument and the Pushback channel id as the second one.
#!/bin/bash # habits.sh TITLE=$1 # First argument CHANNEL=$2 # Second argument RESPONSE=$(curl -s https://api.pushback.io/v1/send_sync \ -u <at_token>: \ -d "id=$CHANNEL" \ -d "title=$TITLE" \ -d "action1=Done" \ -d "reply=Excuse") if [[ $RESPONSE == "Done" ]]; then DATE=$(date +%s) echo "$DATE:$TITLE $RESPONSE" >> habits.log fi
After I create a channel in Pushback I can track each of my habits.
0 21 * * * habits "Floss" "Channel_25" 0 7 * * 1,3,5 habits "Exercise" "Channel_26" # every Monday, Wednesady and Friday at 7:00AM 0 12 * * * habits "Eat healthy" "Channel_27"
I'll have a history in my log file, that I can turn into fancy graphs with munin or grafana later on, but I'll also have a message history I can look back on.
For maintenance tasks, I want the notification to appear when it needs to be done, but I also want it to constantly bug me until I complete the task. So for example, I'll change my house's air filter every 3 months. Once 3 months comes up, I want a notification to always be on my phone until I hit Done. I'll stick the api call to Pushback in a forever for loop for optimal annoy-ness.
#!/bin/bash # maintenance.sh TITLE=$1 # First argument CHANNEL=$2 # Second argument # Bug me until I do it while true do # Sync mode will block until a response is received or the connection dies # specify --max-time to ensure one reminder a day it's not complete RESPONSE=$(curl --max-time 86400 -s https://api.pushback.io/v1/send_sync \ -u <at_token>: \ -d "id=$CHANNEL" \ -d "title=$TITLE" \ -d "action1=Done") if [[ $RESPONSE == "Done" ]]; then DATE=$(date +%s) echo "$DATE:$TITLE $RESPONSE" >> maintenance.log exit 0 fi sleep 60 done
Then I can schedule my cronjobs.
30 9 1 Jan,Apr,Jul,Oct * maintenance.sh "Change house air filter" "Channel_28" 0 0 1 */6 * maintenance.sh "Change car oil" "Channel_29" 0 0 1 */4 * maintenance.sh "Clean out fridge" "Channel_30"
I think the thing that will be nice about these is I can have a record of the day I actually did it.
For my improvement goal I just want a notification once a month. Once I complete the task, I don't want it to remind me anymore. I decided to write to file when the goal is complete, and not send the notification anymore after that.
#!/bin/bash # improvement.sh TITLE=$1 # First argument CHANNEL=$2 # Second argument if [ -f "$TITLE" ]; then echo "$TITLE is complete" exit 0 fi RESPONSE=$(curl -s https://api.pushback.io/v1/send_sync \ -u <at_token>: \ -d "id=$CHANNEL" \ -d "title=$TITLE" \ -d "action1=Done") if [[ $RESPONSE == "Done" ]]; then DATE=$(date +%s) # write to file echo "$DATE:$TITLE $RESPONSE" > "$TITLE" fi
Setting up the cronjobs to run once a month.
0 0 1 * * improvement.sh "Read 1 book" "Channel_31" 0 0 1 * * improvement.sh "Fix light switch" "Channel_32"
Testing it out
To test things out I sent a notification to each channel. Pushback shows all of the different channels in one main dashboard, which is great for a quick overview.
Using cronjobs probably wasn't the easiest way to track my new year's resolutions, but I had fun doing it. I look forward to seeing how I do this year. Happy New Year!