John2809
Posts: 32
Joined: Thu Aug 02, 2018 9:49 pm

Adding inputs to existing tkinter stopwatch code

Fri Aug 03, 2018 7:59 pm

Hi ,

I,m looking for some help with the following code , im new to programming however managed to string this together by compiling code for different websites. Im wanting to use a gui stopwatch display controlled via the gpio pins .

input 1 = start the timer
input 2 N/O = stop the timer when it goes N/C
input 3 N/C= stop the timer when it goes N/O
input 4 = reset timer
Output 1 = turn on Relay from gpio pin , when input 2 or 3 changes state ,turn off relay when the reset is pushed. Im unsure how to add this into the following code .

Regards

John

import Tkinter as tk
from threading import Thread
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BOARD)
GPIO.setup(7,GPIO.IN)
GPIO.setup(8,GPIO.IN)
GPIO.setup(10,GPIO.IN)
GPIO.setup(12,GPIO.IN)
GPIO.setup(13,GPIO.OUT)


# Note: Python 2.6 or higher is required for .format() to work
def update_timeText():
if (state):
global timer
# Every time this function is called,
# we will increment 1 centisecond (1/100 of a second)
timer[2] += 1

# Every 100 centisecond is equal to 1 second
if (timer[2] >= 100):
timer[2] = 0
timer[1] += 1
# Every 60 seconds is equal to 1 min
if (timer[1] >= 60):
timer[0] += 1
timer[1] = 0
# We create our time string here
timeString = pattern.format(timer[0], timer[1], timer[2])
# Update the timeText Label box with the current time
timeText.configure(text=timeString)
# Call the update_timeText() function after 1 centisecond
root.after(10, update_timeText)

# To start the timer
def start():
global state
state = True

# To pause the kitchen timer
def pause():
global state
state = False

# To reset the timer to 00:00:00
def reset():
global timer
timer = [0, 0, 0]
timeText.configure(text='00:00:00')

# To exist our program
def exist():
root.destroy()

# Simple status flag
# False mean the timer is not running
# True means the timer is running (counting)
state = False

root = tk.Tk()
root.wm_title('Secondary Injection Timer By John Halliwell')

button_frame = tk.Frame(root)
button_frame.pack(fill=tk.X, side=tk.BOTTOM)

start_button = tk.Button(button_frame, text='Start', command=start)
stop_button = tk.Button(button_frame, text='Stop', command=pause)
reset_button = tk.Button(button_frame, text='Reset', command=reset)
quit_button = tk.Button(button_frame, text='Quit', command=exist)

button_frame.columnconfigure(0, weight=1)
button_frame.columnconfigure(1, weight=1)
button_frame.columnconfigure(2, weight=1)
button_frame.columnconfigure(3, weight=1)

start_button.grid(row=0, column=0, sticky=tk.W+tk.E)
stop_button.grid(row=0, column=1, sticky=tk.W+tk.E)
reset_button.grid(row=0, column=2, sticky=tk.W+tk.E)
quit_button.grid(row=0, column=3, sticky=tk.W+tk.E)

# Our time structure [min, sec, centsec]
timer = [0, 0, 0]
# The format is padding all the
pattern = '{0:02d}:{1:02d}:{2:02d}'

# Create a timeText Label (a text box)
timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 200))
timeText.pack()


update_timeText()
root.mainloop()

User avatar
paddyg
Posts: 2161
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Adding inputs to existing tkinter stopwatch code

Sat Aug 04, 2018 8:39 pm

Well most people will be put off by your un-formatted post. You need to use code tags (see sticky post at the top). Unless you have a very strong reason not to (and I couldn't see one in your code) you should use python3. i.e. import tkinter as tk.

w.r.t your GPIO question you should, IMO, use https://gpiozero.readthedocs.io/en/stab ... tml#button which will make your life much easier. Basically you want to call the functions you've defined when buttons get pressed.

If you check the elapsed time between pressing the start and pause you will see that your timer is VERY inaccurate, the tk callback system isn't really designed for this kind of thing. It's much better to use the computer clock and look at the elapsed time. Here's a half baked version to give you the idea, I've not tested it but you should be able to work out what to do by looking at the documentation.

Code: Select all

import tkinter as tk
from threading import Thread
import time

import gpiozero

b_start = gpiozero.Button(4, pull_up=True)#... look up arguments you need)
b_start.when_pressed(start)
b_pause = gpiozero.Button(14, pull_up=True) #...
b_pause.when_pressed(pause)
b_pause_alt = gpiozero.Button(15, pull_up=False)
b_pause_alt.when_pressed(pause)
b_reset = gpiozero.Button(18, pull_up=True)
b_reset.when_pressed(reset)

relay = gpiozero.OutputDevice(27)

# Note: Python 2.6 or higher is required for .format() to work
def update_timeText():
    global start_tm, previous_tm
    tm = previous_tm
    if state:
        tm += time.time() - start_tm
    mins = int(tm / 60)
    secs = int(tm % 60)
    frac = int((tm * 100) % 100)
    # We create our time string here
    timeString = pattern.format(mins, secs, frac)
    # Update the timeText Label box with the current time
    timeText.configure(text=timeString)
    # Call the update_timeText() function after 1 centisecond
    root.after(10, update_timeText)

# To start the timer
def start():
    global state, start_tm
    if not state:
        start_tm = time.time()
    state = True

# To pause the kitchen timer
def pause():
    global state, previous_tm
    if state: #i.e. timer running
        previous_tm += time.time() - start_tm
    state = False
    relay.on()

# To reset the timer to 00:00:00 NB doesn't stop time. If you want that behavior then just add 'pause()' line
def reset():
    global start_tm, previous_tm
    previous_tm = 0.0
    start_tm = time.time()
    timeText.configure(text='00:00:00')
    relay.off()

# To exit our program
def exit():
    root.destroy()

# Simple status flag
# False mean the timer is not running
# True means the timer is running (counting)
state = False
start_tm = 0.0
previous_tm = 0.0
root = tk.Tk()
root.wm_title('Secondary Injection Timer By John Halliwell')

button_frame = tk.Frame(root)
button_frame.pack(fill=tk.X, side=tk.BOTTOM)

start_button = tk.Button(button_frame, text='Start', command=start)
stop_button = tk.Button(button_frame, text='Stop', command=pause)
reset_button = tk.Button(button_frame, text='Reset', command=reset)
quit_button = tk.Button(button_frame, text='Quit', command=exit)

button_frame.columnconfigure(0, weight=1)
button_frame.columnconfigure(1, weight=1)
button_frame.columnconfigure(2, weight=1)
button_frame.columnconfigure(3, weight=1)

start_button.grid(row=0, column=0, sticky=tk.W+tk.E)
stop_button.grid(row=0, column=1, sticky=tk.W+tk.E)
reset_button.grid(row=0, column=2, sticky=tk.W+tk.E)
quit_button.grid(row=0, column=3, sticky=tk.W+tk.E)

# Our time structure [min, sec, centsec]
timer = [0, 0, 0]
# The format is padding all the
pattern = '{0:02d}:{1:02d}:{2:02d}'

# Create a timeText Label (a text box)
timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 200))
timeText.pack()


update_timeText()
root.mainloop()
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

John2809
Posts: 32
Joined: Thu Aug 02, 2018 9:49 pm

Re: Adding inputs to existing tkinter stopwatch code

Thu Aug 16, 2018 5:37 pm

Hi Paddy

Thanks for your reply , i wasnt to sure how to post but i can see what you mean now . ive tried to run your code example and im getting the following errors

Any help would be appreciated

John

Code: Select all

Traceback (most recent call last):
  File "/home/pi/Desktop/newtimer.py", line 12, in <module>
    b_start = gpiozero.Button(4, pull_up=True)#... look up arguments you need)
  File "/usr/lib/python3/dist-packages/gpiozero/devices.py", line 95, in __call__
    self = super(GPIOMeta, cls).__call__(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/gpiozero/input_devices.py", line 303, in __init__
    pin, pull_up, bounce_time, pin_factory=pin_factory
  File "/usr/lib/python3/dist-packages/gpiozero/mixins.py", line 338, in __init__
    super(HoldMixin, self).__init__(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/gpiozero/input_devices.py", line 100, in __init__
    self.pin.when_changed = self._fire_events
  File "/usr/lib/python3/dist-packages/gpiozero/pins/__init__.py", line 388, in <lambda>
    lambda self, value: self._set_when_changed(value),
  File "/usr/lib/python3/dist-packages/gpiozero/pins/pi.py", line 289, in _set_when_changed
    self._enable_event_detect()
  File "/usr/lib/python3/dist-packages/gpiozero/pins/rpigpio.py", line 219, in _enable_event_detect
    bouncetime=self._bounce)
RuntimeError: Failed to add edge detection/code]

User avatar
paddyg
Posts: 2161
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Adding inputs to existing tkinter stopwatch code

Thu Aug 16, 2018 7:34 pm

That's odd. I can't reproduce that error but I do get errors further on. Essentially a) the functions need to be defined before allocating to buttons (obviously!!) b) when_pressed is used differently, basically set equal to a function. See my revised code at the bottom which I've just checked on this RPi 3 and seems to work.

How are you running the code? From command line or from an editor? Did you copy and paste it unaltered?

Code: Select all

import tkinter as tk
from threading import Thread
import time

import gpiozero

def update_timeText():
    global start_tm, previous_tm
    tm = previous_tm
    if state:
        tm += time.time() - start_tm
    mins = int(tm / 60)
    secs = int(tm % 60)
    frac = int((tm * 100) % 100)
    timeString = pattern.format(mins, secs, frac)
    timeText.configure(text=timeString)
    root.after(10, update_timeText)

# To start the timer
def start():
    global state, start_tm
    if not state:
        start_tm = time.time()
    state = True

# To pause the kitchen timer
def pause():
    global state, previous_tm
    if state: #i.e. timer running
        previous_tm += time.time() - start_tm
    state = False
    relay.on()

# To reset the timer to 00:00:00 NB doesn't stop time. If you want that behavior then just add 'pause()' line
def reset():
    global start_tm, previous_tm
    previous_tm = 0.0
    start_tm = time.time()
    timeText.configure(text='00:00:00')
    relay.off()

# To exit our program
def exit():
    root.destroy()

b_start = gpiozero.Button(4, pull_up=True)#... look up arguments you need)
b_start.when_pressed = start
b_pause = gpiozero.Button(14, pull_up=True) #...
b_pause.when_pressed = pause
b_pause_alt = gpiozero.Button(15, pull_up=False)
b_pause_alt.when_pressed = pause
b_reset = gpiozero.Button(18, pull_up=True)
b_reset.when_pressed = reset
relay = gpiozero.OutputDevice(27)

# Simple status flag
# False mean the timer is not running
# True means the timer is running (counting)
state = False
start_tm = 0.0
previous_tm = 0.0
root = tk.Tk()
root.wm_title('Secondary Injection Timer By Paddy Gaunt')
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

John2809
Posts: 32
Joined: Thu Aug 02, 2018 9:49 pm

Re: Adding inputs to existing tkinter stopwatch code

Thu Aug 16, 2018 8:58 pm

Hi Paddy ,

Yes I’ve tried from the command line and the editor getting the same error . I copy and paste it into a text editor then same it as a py file . I normally use the editor on previous scripts and don’t normally have issues . Would the problem be me using a rpi 2 ?
B8B920D7-B83C-477B-A156-FCA16618F673.jpeg
B8B920D7-B83C-477B-A156-FCA16618F673.jpeg (243.44 KiB) Viewed 222 times
John

User avatar
DougieLawson
Posts: 33630
Joined: Sun Jun 16, 2013 11:19 pm
Location: Basingstoke, UK
Contact: Website

Re: Adding inputs to existing tkinter stopwatch code

Thu Aug 16, 2018 8:59 pm

Stop using sudo. You don't need it.
Microprocessor, Raspberry Pi & Arduino Hacker
Mainframe database troubleshooter
MQTT Evangelist
Twitter: @DougieLawson

2012-18: 1B*5, 2B*2, B+, A+, Z, ZW, 3Bs*3, 3B+

Any DMs sent on Twitter will be answered next month.

John2809
Posts: 32
Joined: Thu Aug 02, 2018 9:49 pm

Re: Adding inputs to existing tkinter stopwatch code

Thu Aug 16, 2018 9:52 pm

Hi
Found the below issue and changed the GPIO 4 to 11 and it’s stopped the error . However the script windows opens now , but it’s blank inside with no timer showing . I’m going to have another look tomorrow.

John

“Physical pin 7 ( gpio4) is also used as the default pin for the 1-wire interface that may have been what caused your problem, especially if 1-wire interface was enabled.”

User avatar
paddyg
Posts: 2161
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Adding inputs to existing tkinter stopwatch code

Thu Aug 16, 2018 10:17 pm

John, sounds like progress of some kind. Does it work ok if you comment out all the gpio stuff and just use the tk buttons? Try to add code back in a bit at time to narrow down the point where it stops working.
Paddy
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

gordon77
Posts: 3343
Joined: Sun Aug 05, 2012 3:12 pm

Re: Adding inputs to existing tkinter stopwatch code

Fri Aug 17, 2018 8:57 am

Try this, using your original code...
You'll need to interface the relay.

Works OK on my Pi.

Updated as RELAY operation not what you wanted

Code: Select all

import tkinter as tk
from threading import Thread
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(7,GPIO.IN,pull_up_down = GPIO.PUD_UP)    # input 1 START (connect to gnd to START)
GPIO.setup(8,GPIO.IN,pull_up_down = GPIO.PUD_UP)    # input 2 STOP  (connect to gnd to STOP)
GPIO.setup(10,GPIO.IN,pull_up_down = GPIO.PUD_UP)   # input 3 STOP  (DISconnect from gnd to STOP)
GPIO.setup(12,GPIO.IN,pull_up_down = GPIO.PUD_UP)   # input 4 RESET (connect to gnd to RESET)
GPIO.setup(13,GPIO.OUT)
GPIO.output(13, GPIO.LOW) # ensures Relay output OFF


# Simple status flag
# False mean the timer is not running
# True means the timer is running (counting)
state = False


# Note: Python 2.6 or higher is required for .format() to work
def update_timeText():
   global state
   if state == False and GPIO.input(7) == 0 and GPIO.input(8) == 1 and GPIO.input(10) == 0 and GPIO.input(12) == 1:
      state = True
      GPIO.output(13, GPIO.LOW)
   elif state == True and (GPIO.input(8) == 0 or GPIO.input(10) == 1):
      state = False
      if timer != [0, 0, 0]:
         GPIO.output(13, GPIO.HIGH)
   if GPIO.input(12) == 0:
      global timer
      timer = [0, 0, 0]
      timeText.configure(text='00:00:00')
      state = False
      GPIO.output(13, GPIO.LOW)
   if state:
      GPIO.output(13, GPIO.LOW)
      global timer
# Every time this function is called, 
# we will increment 1 centisecond (1/100 of a second)
      timer[2] += 1
      # Every 100 centisecond is equal to 1 second
      if (timer[2] >= 100):
         timer[2] = 0
         timer[1] += 1
         # Every 60 seconds is equal to 1 min
         if (timer[1] >= 60):
            timer[0] += 1
            timer[1] = 0
   
# We create our time string here
   timeString = pattern.format(timer[0], timer[1], timer[2])
# Update the timeText Label box with the current time
   timeText.configure(text=timeString)
# Call the update_timeText() function after 1 centisecond
   root.after(10, update_timeText)

# To start the timer
def start():
   global state
   state = True

# To pause the kitchen timer
def pause():
   global state
   state = False
   if timer != [0, 0, 0]:
      GPIO.output(13, GPIO.HIGH)

# To reset the timer to 00:00:00
def reset():
   global timer
   timer = [0, 0, 0]
   timeText.configure(text='00:00:00')
   GPIO.output(13, GPIO.LOW)

# To exist our program
def exist():
   root.destroy()

root = tk.Tk()
root.wm_title('Secondary Injection Timer By John Halliwell')

button_frame = tk.Frame(root)
button_frame.pack(fill=tk.X, side=tk.BOTTOM)

start_button = tk.Button(button_frame, text='Start', command=start)
stop_button = tk.Button(button_frame, text='Stop', command=pause)
reset_button = tk.Button(button_frame, text='Reset', command=reset)
quit_button = tk.Button(button_frame, text='Quit', command=exist)

button_frame.columnconfigure(0, weight=1)
button_frame.columnconfigure(1, weight=1)
button_frame.columnconfigure(2, weight=1)
button_frame.columnconfigure(3, weight=1)

start_button.grid(row=0, column=0, sticky=tk.W+tk.E)
stop_button.grid(row=0, column=1, sticky=tk.W+tk.E)
reset_button.grid(row=0, column=2, sticky=tk.W+tk.E)
quit_button.grid(row=0, column=3, sticky=tk.W+tk.E)

# Our time structure [min, sec, centsec]
timer = [0, 0, 0]
# The format is padding all the 
pattern = '{0:02d}:{1:02d}:{2:02d}'

# Create a timeText Label (a text box)
timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 200))
timeText.pack()

update_timeText()
root.mainloop()


John2809
Posts: 32
Joined: Thu Aug 02, 2018 9:49 pm

Re: Adding inputs to existing tkinter stopwatch code

Sat Aug 18, 2018 3:15 pm

Hi Gordon

Thanks for your help , im still having issues, the program runs but very slow and the buttons or pins are not starting the timer for some reason . :(

I have a program that seems to work alot quicker, but would it be possible to add your code into it so i can use the GPIO as inputs . Ive added the GPIO bits at the top but unsure where to put the code into the rest .

Thanks John

Code: Select all

from Tkinter import *
import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(7,GPIO.IN,pull_up_down = GPIO.PUD_UP)    # input 1 START (connect to gnd to START)
GPIO.setup(8,GPIO.IN,pull_up_down = GPIO.PUD_UP)    # input 2 STOP  (connect to gnd to STOP)
GPIO.setup(10,GPIO.IN,pull_up_down = GPIO.PUD_UP)   # input 3 STOP  (DISconnect from gnd to STOP)
GPIO.setup(12,GPIO.IN,pull_up_down = GPIO.PUD_UP)   # input 4 RESET (connect to gnd to RESET)
GPIO.setup(13,GPIO.OUT)
GPIO.output(13, GPIO.LOW) # ensures Relay output OFF
state = False

class StopWatch(Frame):  
    """ Implements a stop watch frame widget. """                                                                
    def __init__(self, parent=None, **kw):        
        Frame.__init__(self, parent, kw)
        self._start = 0.0        
        self._elapsedtime = 0.0
        self._running = 0
        self.timestr = StringVar()               
        self.makeWidgets()      

    def makeWidgets(self):                         
        """ Make the time label. """
        l = Label(self, textvariable=self.timestr)
        self._setTime(self._elapsedtime)
        l.pack(fill=X, expand=NO, pady=2, padx=2)                      

    def _update(self): 
        """ Update the label with elapsed time. """
        self._elapsedtime = time.time() - self._start
        self._setTime(self._elapsedtime)
        self._timer = self.after(50, self._update)
        
    def _setTime(self, elap):
        """ Set the time string to Minutes:Seconds:Hundreths """
        minutes = int(elap/60)
        seconds = int(elap - minutes*60.0)
        hseconds = int((elap - minutes*60.0 - seconds)*100)                
        self.timestr.set('%02d:%02d:%02d' % (minutes, seconds, hseconds))

    def Start(self):                                                     
        """ Start the stopwatch, ignore if running. """
        if not self._running:            
            self._start = time.time() - self._elapsedtime
            self._update()
            self._running = 1
           
            
    def Stop(self):                                    
        """ Stop the stopwatch, ignore if stopped. """
        if self._running:
            self.after_cancel(self._timer)            
            self._elapsedtime = time.time() - self._start    
            self._setTime(self._elapsedtime)
            self._running = 0
      
    def Reset(self):                                  
        """ Reset the stopwatch. """
        self._start = time.time()         
        self._elapsedtime = 0.0    
        self._setTime(self._elapsedtime)

def main():

    root = Tk()
    sw = StopWatch(root)
    sw.pack(side=TOP)

    Button(root, text='Start', command=sw.Start).pack(side=LEFT)
    Button(root, text='Stop', command=sw.Stop).pack(side=LEFT)
    Button(root, text='Reset', command=sw.Reset).pack(side=LEFT)
    Button(root, text='Quit', command=root.quit).pack(side=LEFT)

    root.mainloop()

if __name__ == '__main__':
    main()

gordon77
Posts: 3343
Joined: Sun Aug 05, 2012 3:12 pm

Re: Adding inputs to existing tkinter stopwatch code

Sat Aug 18, 2018 4:05 pm

Worked OK on my pi. Did you have pin 10 to gnd before you started?

Take a look at your other thread, code supplied
https://www.raspberrypi.org/forums/view ... p?t=220614

Return to “Python”

Who is online

Users browsing this forum: No registered users and 13 guests