[Home] [Articles, Categories, Tags] [Books, Quotes]
Simple Timers
Tags:
Posted: 2016-09-23
Last Update: 2016-09-23
# TODO: - link to zenity

A few years ago I would constantly burn whatever I was cooking. The story was always the same: I would put something on the stove, go back to the computer, and wait until the smoke detector reminded me I had burned dinner, again. Eventually I wrote a simple bash script using zenity to act as a sort of egg timer. My timer is linked to meta-T. Once called it prompts you to type in the number of minutes you want to be reminded in. This worked very well and I haven't burned any food in years! After a while though, I wanted a few more features.

timer.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/bin/bash
#Mark Feineigle 2014 03 14
#Wait x time, then play sound/note & prompt for input. On input "0" close, on input "-ge 1" loop 

END_SOUND="/home/egg/.sounds/river_done.wav"
#FUNCTIONS
timer () {
  while [ $TIME -ge 1 ]  2>/dev/null #loop while TIME >0
  do
    if [ $1 == "-m" ]; then
      let TIME=$TIME*60 #multiply for minutes
      TITLE="Minutes";TEXT="minutes" #set labels for use in zenity
    else
      TITLE="Seconds";TEXT="seconds" #set labels for use in zenity
    fi
    sleep $TIME #sleep for TIME
    aplay $END_SOUND > /dev/null 2>&1 & #play sound, suppress output, run in background
    if [ $NOTE != "" ]  2>/dev/null; then #if there is a NOTE, display it
      zenity --title="Reminder" --info --text="$NOTE"
    fi
    export TIME=`zenity --title="$TITLE" --entry --text="More $TEXT?"` #input TIME from GUI
    if [ $TIME == "0" -o $TIME == "" ]  2>/dev/null; then #if TIME = 0 of null
      exit 0
    fi
    NOTE="" #clear old note
    if [ $TIME -ge 11 ] 2>/dev/null; then #if TIME is longer than x
      export NOTE=`zenity --title="Reminder" --entry --text="Note?"` # input NOTE from GUI
    fi
  done
  exit 0
}
#START OF MAIN
if [ "$1" == "-s" -a "$2" -ge 1 ] 2>/dev/null; then  #if the 1st arg is "-s" and 
                                                     #the 2nd arg is >=1
  TIME="$2";NOTE="$3" #set 2nd/3rd args as TIME/NOTE
  timer $1 #pass $1 (-s) to timer function
elif [ "$1" == "-s" -a "$2" == "" ]; then #if no 2nd arg
  export TIME=`zenity --title="Seconds" --entry --text="How many seconds?"` #read SECONDS 
  if [ $TIME == "0" -o $TIME == "" ] 2>/dev/null; then #if 0 or null
    exit 0
  fi
  if [ $TIME -ge 3 ] 2>/dev/null; then #if TIME longer than x
    export NOTE=`zenity --title="Reminder" --entry --text="Note?"` # add NOTE from GUI
  fi
  timer $1 #$TIME $NOTE   #call timer function, exported TIME/NOTE = no passing needed?
elif [ "$1" == "-m" -a  "$2" -ge 1 ] 2>/dev/null; then #if 1st arg is "-m" and 2nd arg is >0
  TIME="$2";NOTE="$3" #set 2nd/3rd args as TIME/NOTE
  timer $1 #pass $1 (-m) to timer function
elif [ "$1" == "-m" -a "$2" == "" ]; then #GUI prompt for integer
  #return MINUTES from GUI
  export TIME=`zenity --title="Minutes" --entry --text="How many minutes?"`
  if [ $TIME == "0" -o $TIME == "" ] 2>/dev/null; then #if 0 of null
    exit 0
  fi
  if [ $TIME -ge 9 ] 2>/dev/null; then #if TIME longer than x
    # add NOTE from GUI
    export NOTE=`zenity --title="Reminder" --entry --text="Note?"`
  fi
  timer $1 #$TIME $NOTE   #call timer function, exported TIME/NOTE = no passing needed?
elif [ "$1" -ge 1 ]  2>/dev/null; then #if 1st arg is >0
  TIME="$1";NOTE="" #set TINE as 1st arg, NOTE as null
  timer -m #call timer function with $1 = "=m"
else
  printf "minutes usage = $0 [MINUTES]\n"
  printf "              = $0 -m [MINUTES]\n\n" #display help on any non-defined useage
  printf "seconds usage = $0 -s [SECONDS]\n\n"
  printf "this help     = $0 -h\n"
  printf "        = $0 --help\n\n"
fi
exit 0

Finding an excuse to learn some Qt, I wrote a new version of the timer in python. This version works much the same way, but with a few extra features. After an alarm sounds the program starts counting up, letting you know how long ago the initial alarm sounded. Next, it emits its alarm sound every 5 minutes after the initial alarm sounds. This isn't too important when used as an egg timer, but now it can be issued a 0 minute timer that alerts immediately and then counts up. It keeps track of how long has been spent on a particular task and also sounds off with 5 minute metering.

timer.py

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env python
#Author: Mark Feineigle
#Create Date: 2016/08/21
#Last Modify: 2016/08/22
'''
A replacement for my bash timer script, timer.sh
'''
#TODO: better variable names
# layout
# hide title bar DONE
#  disables esc to close
# icon
# highlight tab order
import commands #use aplay to play sound
import sys #argv for qt
from PyQt4 import QtGui, QtCore
import time #asctime

END_SOUND = "/home/USER/.sounds/quiet_river_done.wav"

class myDialog(QtGui.QDialog):
  '''The 'main' timer window'''
  def __init__(self, parent=None):
    super(myDialog, self).__init__(parent)
    #variables
    self.counter = 0 #counter
    self.flag = False #flag for counting or not
    #text inputs
    self.inp = QtGui.QLineEdit("0")
    self.connect(self.inp, QtCore.SIGNAL("returnPressed()"), self.sleepTimerOn) 
    self.note = QtGui.QLineEdit("Note")
    self.connect(self.note, QtCore.SIGNAL("returnPressed()"), self.sleepTimerOn) 
    #buttons
    #NOTE this button has no purpose, without it the first button created is
    # called after sleepTimerOn, no idea...
    #NOTE now that i've broken sleep into 2 functions, this is required to not 
    # start the counter when a non-int is entered...
    #NOTE adding a quit button seems to work...
    self.countbtn = QtGui.QPushButton("Quit", self)
    #TODO how to link to esc?
    self.connect(self.countbtn, QtCore.SIGNAL("escapePressed()"), self.quit) 
    #self.countbtn.hide()
    self.countbtn.clicked.connect(self.quit)
    self.startbtn = QtGui.QPushButton("On/Off", self)
    self.startbtn.clicked.connect(self.countToggle)
    self.sleepbtn = QtGui.QPushButton("Sleep", self)
    self.sleepbtn.clicked.connect(self.sleepTimerOn)
    #labels
    self.msgLbl = QtGui.QLabel("")
    t = self.formatTime(self.counter)
    self.counterLbl = QtGui.QLabel(
           "<font color=white size=6 style='font-family:Monospace;'><b>"
                   +str(t)+
                   "</b></font>")
    #grid
    grid = QtGui.QGridLayout()
    grid.addWidget(self.counterLbl, 1, 2) #matplot like coords
    #TODO better layout for changing label size
    grid.addWidget(self.msgLbl, 1, 1) #matplot like coords
    grid.addWidget(self.inp, 1, 4) #matplot like coords
    grid.addWidget(self.note, 2, 1) #matplot like coords
    grid.addWidget(self.countbtn, 2, 2)
    grid.addWidget(self.startbtn, 2, 3)
    grid.addWidget(self.sleepbtn, 2, 4)
    self.setLayout(grid)

    self.setWindowTitle("Tick tock mother fucker")
    self.inp.setFocus()
    self.show()

  def sleepTimerOn(self):
    '''Connected to sleepbtn and inp box. 
    Hides the window and sleeps.'''
    #print self.flag, "1"
    self.startTime = time.asctime().split()[3]
    try:
      t = int(self.inp.displayText()) #get input
      self.hide() #if successful in converting to input to int
      QtCore.QTimer.singleShot(t*60*1000, self.sleepTimerOff) #wait milliseconds then..loop
    except:
      sys.exit() #input was not an int
    finally:
      self.inp.setFocus()

  def sleepTimerOff(self):
    '''Called from sleepTimerOn
    Resets counter when it wakes up.'''
    self.stopTime = time.asctime().split()[3]
    msg = "Slept {} mins\n{}\n{}".format(self.inp.displayText(),
      self.startTime, self.stopTime)
    self.msgLbl.setText(msg)
    self.counter = 0 #start counting up from 0 after timer expires
    #print self.flag, "2"
    if self.flag == False:
      self.countToggle()
    commands.getoutput("aplay "+END_SOUND)
    self.show()
    #print self.flag, "7"

  def countToggle(self):
    '''Connected to startbtn'''
    #print self.flag, "3" 
    self.flag = not self.flag
    if self.flag:
      self.countUp()
    #print self.flag, "6"

  def countUp(self):
    '''Counting loop'''
    #print self.flag, "4"
    if self.flag:
      self.counter+=1
      if not self.counter%300:
    print "minute passed"
    commands.getoutput("aplay "+END_SOUND)
      t = self.formatTime(self.counter)
      self.counterLbl.setText(
                    "<font color=white size=6 style='font-family:Monospace'><b>"
                    +str(t)+
                    "</b></font>")
      QtCore.QTimer.singleShot(1000, self.countUp) #counts the (milli)seconds
    #print self.flag, "5"

  def formatTime(self, t):
    '''Helper to display nicely formatted times'''
    minutes = t/60
    seconds = t%60
    if seconds < 10:
      seconds = "0"+str(seconds)
    return str(minutes)+":"+str(seconds)

  def quit(self):
    sys.exit()

def main():
  app = QtGui.QApplication(sys.argv)
  myDia = myDialog()
  #TODO hide titlebar
  # add icon
  #TODO highlight selected element w/ tab
  #myDia.setWindowFlags(QtCore.Qt.SplashScreen) #hides the default titlebar
  #TODO center window on screen and link esc
  #TODO spacebar to start/stop button
  myDia.show()
  app.exec_()

if __name__ == '__main__':
  main()
Comments:

2016-10-02 07:38:33

[I am He-Man!]
I am the ARTICLE master of the universe.

2016-10-07 01:23:36

[I am He-Man!]
I am the ARTICLE master of the universe.

2016-10-07 01:26:55

[I am He-Man!]
I am the ARTICLE master of the universe.

2016-10-15 01:26:35

[I am He-Man!]
I am the ARTICLE master of the universe.











[About] [Contact]