SaerX
Posts: 1
Joined: Thu Dec 18, 2014 1:30 pm

Multiple timers controlling I2C output

Mon Feb 16, 2015 1:19 pm

Hi,

First post here, so I thought the beginners section would be best for now, especially since I'm quite new to Python. I've done some embedded work some years ago, so basic electronics needed here is pretty much straightforward and I mostly see a need for coding advice.

I'm looking to make a program (in Python -- but C isn't out of the question, if it's a far better choice; timing accuracy here isn't down to microseconds, but rather, a few seconds) to be able to independently turn on and latch an output for X minutes, with a system having up to 16 outputs. These outputs are supposed to stay on for a pre-set number of minutes to provide a device with power and then, once the set amount of minutes has passed, turn off to wait for a new "on" command to start running the timer again. Independent one-shot timers, in short, I guess.

In the end, I plan on having a touch screen GUI with, for example, a set of 4 x 4 boxes to represent these outputs that you can start/stop/reset individually by tapping on the desired box, but I'm not exactly sure how to start with the entire program. The outputs will be handled with a PCA9865-based I2C PWM board (but no PWM, just on/off for now, so duty cycle would be 0 % or 100 %). The GUI isn't something I need straight away, though, but rather getting the timers running independently of each other in a stable manner.

It would be most useful if everything was scalable, so I could set the number of outputs as a global constant, as well as set up the possible programs in code, each with its own amount of minutes. The amount of minutes would be given by a master selector (may end up being a physical multi-position switch) that is read when a timer is started to give the timer the required running time.

How should I structure the program to make is reasonably elegant and efficient? Threading, so that each output is controlled by a thread that is started by tapping the "box" and then gotten rid of once the timer runs down to zero? Does Python handle 16 simultaneous threads well? How about timestamping the start event and then comparing the current time with the starting time to see if their subtraction is long enough to warrant a stop and reset?

Sorry for the longish post, I know I'm probably asking quite a bit.. ;)


-S

prairietech
Posts: 28
Joined: Wed Mar 20, 2013 9:22 pm

Re: Multiple timers controlling I2C output

Thu Mar 05, 2015 9:27 pm

I found this post using google and your application is very similar to mine. Sorry to see you haven't got an answer. Maybe I can bump your post enough to get the wizards to offer some suggestions.

scotty101
Posts: 3649
Joined: Fri Jun 08, 2012 6:03 pm

Re: Multiple timers controlling I2C output

Thu Mar 05, 2015 9:40 pm

No need for independent threads.

When button 1 is pressed you will record the current time. The programming will then periodically check to see if 5 minutes has elapsed.
If I get a chance I'll throw together a simple python app with a Tkinter GUI as an example.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

prairietech
Posts: 28
Joined: Wed Mar 20, 2013 9:22 pm

Re: Multiple timers controlling I2C output

Thu Mar 05, 2015 9:47 pm

Thanks! I'll watch this thread for your code.

User avatar
Douglas6
Posts: 4711
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Multiple timers controlling I2C output

Thu Mar 05, 2015 9:49 pm

Not surprisingly, the Python Timer class (a special purpose subclass of Thread), is probably the easiest way to go. The target function would simply turn off the GPIO. Create as many as you like, with an argument indicating which GPIO.

https://docs.python.org/2/library/threa ... er-objects

scotty101
Posts: 3649
Joined: Fri Jun 08, 2012 6:03 pm

Re: Multiple timers controlling I2C output

Fri Mar 06, 2015 9:40 am

Hello, 15 minutes of coding later and 5 minutes of documentation, an example program.

This is written for python3 and roughly meets your brief but with enough left out so you can learn. When you press a button, a timer event is added to a list to expire in 5 seconds and the button is disabled
When the timer expires, the button becomes active again.
Try pressing all the buttons in a random order and see what happens over the next 10-15 seconds.

There are, of course, other ways of doing this, like the Timer method mentioned by the last poster.

Code: Select all

from tkinter import *
import time

class App(Frame):
    def __init__(self,master,**kw):
        """Create the user interface with a 3x3 button grid."""
        Frame.__init__(self,master)
        buttons = (('Light1',0,0),
                   ('Light2',0,1),
                   ('Light3',0,2),
                   ('Light4',1,0),
                   ('Light5',1,1),
                   ('Light6',1,2),
                   ('Light7',2,0),
                   ('Light8',2,1),
                   ('Light9',2,2))
        self.buttons = []
        for (num,(name,r,c)) in enumerate(buttons):
            cmd = lambda x=num: self.click(x)
            self.buttons.append(Button(self,text=name,width=4,height=2,command=cmd))
            self.buttons[-1].grid(column=c,row=r)
        self.timer_list = []
        self.update()
        
    def click(self,button):
        """When the button is clicked
        1. Calculate when the timer should expire
        2. Disable this button to prevent multiple events for a single button
        3. Turn the Light On
        4. Add the light event to timer list"""
        time_delay = 10
        timer_expires_at = time.time()+time_delay
        self.buttons[button]['state'] = DISABLED
        self.turn_light_on(button)
        self.timer_list.append((button,timer_expires_at))
        
    def update(self):
        """When update is periodically called
        1. For each item in the timer_list
        1.1 Determine if the time has elapsed, if so
        1.1.1 Remove this event from the list
        1.1.2 Make the button active again
        1.1.3 Turn the light off
        2. Call this update function again in 1 second"""
        for event in self.timer_list:
            (button_num,elapsed_time) = event
            #if the event has passed, remove the event and enable the button
            #print(elapsed_time,time.time(),(time.time()-elapsed_time))
            if elapsed_time < time.time():
                print("Event Removed")
                self.timer_list.remove(event)
                self.buttons[button_num]['state'] = ACTIVE
                self.turn_light_off(button_num)
        #Do this all over again 1000ms later        
        self.timer = self.after(1000,self.update)
        
    def turn_light_on(self,light_num):
        print("Turning On Light ",light_num)
        #Insert your code to turn light on here

    def turn_light_off(self,light_num):
        print("Turning Off Light ",light_num)
        #Insert your code to turn light off here

                   
        
def main():
    """Create a root Tkinter instance to contain our App"""
    root = Tk()
    root.title("Light Controller")
    app = App(root)
    app.grid()
    root.mainloop()


if __name__ == '__main__':
    main()         

Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

Return to “Beginners”