Cronjob your New Year's resolutions

D
Dan Willoughby・ Dec 31, 20196 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.

  1. Habits (daily)

    • Eat healthy each meal
    • Exercise 3 times a week
    • Floss teeth daily
  2. Repeating Maintenance (bi-monthly, semi-annual, etc)

    • Change house air filter
    • Change car oil
    • Clean out fridge
  3. Improvement goals (complete once)

    • Read 1 book
    • Fix light switch

My strategy

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.

Habits

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.

Created channels in pushback
Created channels in pushback

Repeating maintenance

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.

Improvement Goals

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.

Testing out each script
Testing out each script

Conclusion

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!


WRITTEN BY

Dan Willoughby

Hi I'm Dan and I like to code and build things. Sometimes when I program, it's useful, othertimes it's not as useful. You can watch me code live on Twitch!