triangula.util: Helpful Things

The triangula.util package contains functionality that’s generally useful but which doesn’t belong anywhere else. At the moment this includes a function to get the current IP address and a class triangula.util.IntervalCheck which is incredibly helpful when handling potentially slow responding hardware, or hardware which cannot be polled at above a certain rate, within a fast polling loop such as Triangula’s task framework or PyGame’s event loop.

Using IntervalCheck

You’ll often find you’re running code in an event loop, this is a loop which has to run as fast as possible and which services everything you need to handle - input, output, providing feedback, reading sensors etc. Some of your sensors or output devices probably can’t keep up with this rate, and it’s possible you want to do expensive calculations that don’t have to be done on every single iteration through the loop. You want the loop to complete as fast as possible to keep everything responsive, so littering your code with time.sleep() calls is a bad idea, but you also need to ensure that e.g. you only update your motor speeds at most twenty times per second.

The triangula.util.IntervalCheck can be used in several different ways to handle several corresponding timing issues:

Rate limiting

You want to update e.g. an LCD display within a fast polling event loop, but the display will flicker like mad if you try to update every time around the loop, and the delay imposed by performing the update will unreasonably slow down everything else.

from triangula.util import IntervalCheck
once_per_second = IntervalCheck(interval = 1)
while 1:
    if once_per_second.should_run():
        # Do the thing that must happen at most once per second
        pass
    # Do the stuff that has to happen every time around the loop
    pass

This will ensure that the code within the if statement will only be run at most once per second. Note that this makes no guarantee about delays between the code finishing and the next iteration starting - if the code in this block takes exactly a second to run there will be no delays at all.

Delay padding

You have a piece of hardware which can be written to or read from, but you must leave at least a certain delay between consecutive operations. You don’t want to just use time.sleep() because you’d like to be able to get on with other things while you wait.

You can use two different kinds of delay here. The first will sleep for a minimum delay since the last time the sleep method was called:

from triangula.util import IntervalCheck
delay = IntervalCheck(interval = 1)
while 1:
    # If it's been less than a second since we last ran, sleep until it'll be exactly a second
    delay.sleep()
    # Run the thing you want to run
    pass

This, again, makes no guarantee that there will actually be a delay. The second’s delay (in this case) is counted from when the previous sleep() call was made. There will be cases where you absolutely must have a delay between a block of code completing and the next time that same block is called, for this you can use the with binding provided by the IntervalCheck:

from triangula.util import IntervalCheck
padding = IntervalCheck(interval = 1)
while 1:
    with padding:
        # Any code here will be run immediately the first time, then on
        # subsequent occasions, on entry to the ``with`` block there will
        # be a pause if required such that the time from the previous
        # completion of the ``with`` block to the start of this one is at
        # least one second
        pass
class triangula.util.IntervalCheck(interval)[source]

Utility class which can be used to run code within a polling loop at most once per n seconds. Set up an instance of this class with the minimum delay between invocations then enclose the guarded code in a construct such as if interval.should_run(): - this will manage the scheduling and ensure that the inner code will only be called if at least the specified amount of time has elapsed.

This class is particularly used to manage hardware where we may wish to include a hardware read or write in a fast polling loop such as the task manager, but where the hardware itself cannot usefully be written or read at that high rate.

Instances of this class can also be used in ‘with’ clauses, i.e. ‘with interval:’ - this will sleep if required before running the gated code, then set the last run time to be the current time. This is not quite the same as just calling sleep() before running a code block, as it resets the time after the code has run, instead of after the sleep call has completed. Used in this mode therefore the interval is from the end of one code block to the start of the next, whereas normally it is from the start of one code block to the start of the next.

__init__(interval)[source]

Constructor

Parameters:interval (float) – The number of seconds that must pass between True values from the should_run() function
should_run()[source]

Determines whether the necessary interval has elapsed. If it has, this returns True and updates the internal record of the last runtime to be ‘now’. If the necessary time has not elapsed this returns False

sleep()[source]

Sleep, if necessary, until the minimum interval has elapsed. If the last run time is not set this function will set it as a side effect, but will not sleep in this case. Calling sleep() repeatedly will therefore not sleep on the first invocation but will subsequently do so each time.

triangula.util.get_ip_address(ifname='wlan0')[source]

Get a textual representation of the IP address for the specified interface, defaulting to wlan0 to pick up our wireless connection if we have one.

Parameters:ifname – Name of the interface to query, defaults to ‘wlan0’
Returns:Textual representation of the IP address
triangula.util.in_range(value, min_value, max_value)[source]

Clamps a value to be within the specified range. If the value is None then None is returned. If either max_value or min_value are None they aren’t used.

Parameters:
  • value – The value
  • min_value – Minimum allowed value
  • max_value – Maximum allowed value