mirror of
				https://github.com/KevinMidboe/python-gpiozero.git
				synced 2025-10-29 17:50:37 +00:00 
			
		
		
		
	While the tests work well on a PC or Travis, the Pi (where I ought to be running them!) has some issues with the timing tests. Need to relax the tolerance of the "assert_states_and_times" method to 0.05 seconds otherwise it periodically fails even on something reasonably quick like a Pi 2 (less failures on a Pi 3 but still occasionally). Also reduced default fps to 25; if the default timing occasionally fails on a Pi 2 it's evidently too fast for a Pi 1 and shouldn't be the default; 25 also doesn't look any different to me on a pulsing LED. There's also a bunch of miscellaneous fixes in here; last minute typos and chart re-gens for the 1.2 release.
		
			
				
	
	
		
			297 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			297 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # vim: set fileencoding=utf-8:
 | |
| 
 | |
| from __future__ import (
 | |
|     unicode_literals,
 | |
|     print_function,
 | |
|     absolute_import,
 | |
|     division,
 | |
| )
 | |
| str = type('')
 | |
| 
 | |
| 
 | |
| from random import random
 | |
| from time import sleep
 | |
| try:
 | |
|     from itertools import izip as zip
 | |
| except ImportError:
 | |
|     pass
 | |
| from itertools import cycle
 | |
| from math import sin, cos, radians
 | |
| try:
 | |
|     from statistics import mean
 | |
| except ImportError:
 | |
|     from .compat import mean
 | |
| 
 | |
| 
 | |
| def negated(values):
 | |
|     """
 | |
|     Returns the negation of the supplied values (``True`` becomes ``False``,
 | |
|     and ``False`` becomes ``True``). For example::
 | |
| 
 | |
|         from gpiozero import Button, LED, negated
 | |
|         from signal import pause
 | |
| 
 | |
|         led = LED(4)
 | |
|         btn = Button(17)
 | |
|         led.source = negated(btn.values)
 | |
|         pause()
 | |
|     """
 | |
|     for v in values:
 | |
|         yield not v
 | |
| 
 | |
| 
 | |
| def inverted(values):
 | |
|     """
 | |
|     Returns the inversion of the supplied values (1 becomes 0, 0 becomes 1,
 | |
|     0.1 becomes 0.9, etc.). For example::
 | |
| 
 | |
|         from gpiozero import MCP3008, PWMLED, inverted
 | |
|         from signal import pause
 | |
| 
 | |
|         led = PWMLED(4)
 | |
|         pot = MCP3008(channel=0)
 | |
|         led.source = inverted(pot.values)
 | |
|         pause()
 | |
|     """
 | |
|     for v in values:
 | |
|         yield 1 - v
 | |
| 
 | |
| 
 | |
| def scaled(values, range_min, range_max, domain_min=0, domain_max=1):
 | |
|     """
 | |
|     Returns *values* scaled from *range_min* to *range_max*, assuming that all
 | |
|     items in *values* lie between *domain_min* and *domain_max* (which default
 | |
|     to 0 and 1 respectively). For example, to control the direction of a motor
 | |
|     (which is represented as a value between -1 and 1) using a potentiometer
 | |
|     (which typically provides values between 0 and 1)::
 | |
| 
 | |
|         from gpiozero import Motor, MCP3008, scaled
 | |
|         from signal import pause
 | |
| 
 | |
|         motor = Motor(20, 21)
 | |
|         pot = MCP3008(channel=0)
 | |
|         motor.source = scaled(pot.values, -1, 1)
 | |
|         pause()
 | |
|     """
 | |
|     domain_size = domain_max - domain_min
 | |
|     range_size = range_max - range_min
 | |
|     for v in values:
 | |
|         yield (((v - domain_min) / domain_size) * range_size) + range_min
 | |
| 
 | |
| 
 | |
| def clamped(values, range_min=0, range_max=1):
 | |
|     """
 | |
|     Returns *values* clamped from *range_min* to *range_max*, i.e. any items
 | |
|     less than *range_min* will be returned as *range_min* and any items
 | |
|     larger than *range_max* will be returned as *range_max* (these default to
 | |
|     0 and 1 respectively). For example::
 | |
| 
 | |
|         from gpiozero import PWMLED, MCP3008, clamped
 | |
|         from signal import pause
 | |
| 
 | |
|         led = PWMLED(4)
 | |
|         pot = MCP3008(channel=0)
 | |
|         led.source = clamped(pot.values, 0.5, 1.0)
 | |
|         pause()
 | |
|     """
 | |
|     for v in values:
 | |
|         yield min(max(v, range_min), range_max)
 | |
| 
 | |
| 
 | |
| def quantized(values, steps, range_min=0, range_max=1):
 | |
|     """
 | |
|     Returns *values* quantized to *steps* increments. All items in *values* are
 | |
|     assumed to be between *range_min* and *range_max* (use :func:`scaled` to
 | |
|     ensure this if necessary).
 | |
| 
 | |
|     For example, to quantize values between 0 and 1 to 5 "steps" (0.0, 0.25,
 | |
|     0.5, 0.75, 1.0)::
 | |
| 
 | |
|         from gpiozero import PWMLED, MCP3008, quantized
 | |
|         from signal import pause
 | |
| 
 | |
|         led = PWMLED(4)
 | |
|         pot = MCP3008(channel=0)
 | |
|         led.source = quantized(pot.values, 4)
 | |
|         pause()
 | |
|     """
 | |
|     range_size = range_max - range_min
 | |
|     for v in scaled(values, 0, 1, range_min, range_max):
 | |
|         yield ((int(v * steps) / steps) * range_size) + range_min
 | |
| 
 | |
| 
 | |
| def conjunction(*values):
 | |
|     """
 | |
|     Returns the `logical conjunction`_ of all supplied values (the result is
 | |
|     only ``True`` if and only if all input values are simultaneously ``True``).
 | |
|     One or more *values* can be specified. For example, to light an
 | |
|     :class:`LED` only when *both* buttons are pressed::
 | |
| 
 | |
|         from gpiozero import LED, Button, conjunction
 | |
|         from signal import pause
 | |
| 
 | |
|         led = LED(4)
 | |
|         btn1 = Button(20)
 | |
|         btn2 = Button(21)
 | |
|         led.source = conjunction(btn1.values, btn2.values)
 | |
|         pause()
 | |
| 
 | |
|     .. _logical conjunction: https://en.wikipedia.org/wiki/Logical_conjunction
 | |
|     """
 | |
|     for v in zip(*values):
 | |
|         yield all(v)
 | |
| 
 | |
| 
 | |
| def disjunction(*values):
 | |
|     """
 | |
|     Returns the `logical disjunction`_ of all supplied values (the result is
 | |
|     ``True`` if any of the input values are currently ``True``). One or more
 | |
|     *values* can be specified. For example, to light an :class:`LED` when
 | |
|     *any* button is pressed::
 | |
| 
 | |
|         from gpiozero import LED, Button, conjunction
 | |
|         from signal import pause
 | |
| 
 | |
|         led = LED(4)
 | |
|         btn1 = Button(20)
 | |
|         btn2 = Button(21)
 | |
|         led.source = disjunction(btn1.values, btn2.values)
 | |
|         pause()
 | |
| 
 | |
|     .. _logical disjunction: https://en.wikipedia.org/wiki/Logical_disjunction
 | |
|     """
 | |
|     for v in zip(*values):
 | |
|         yield any(v)
 | |
| 
 | |
| 
 | |
| def averaged(*values):
 | |
|     """
 | |
|     Returns the mean of all supplied values. One or more *values* can be
 | |
|     specified. For example, to light a :class:`PWMLED` as the average of
 | |
|     several potentiometers connected to an :class:`MCP3008` ADC::
 | |
| 
 | |
|         from gpiozero import MCP3008, PWMLED, averaged
 | |
|         from signal import pause
 | |
| 
 | |
|         pot1 = MCP3008(channel=0)
 | |
|         pot2 = MCP3008(channel=1)
 | |
|         pot3 = MCP3008(channel=2)
 | |
|         led = PWMLED(4)
 | |
|         led.source = averaged(pot1.values, pot2.values, pot3.values)
 | |
|         pause()
 | |
|     """
 | |
|     for v in zip(*values):
 | |
|         yield mean(v)
 | |
| 
 | |
| 
 | |
| def queued(values, qsize):
 | |
|     """
 | |
|     Queues up readings from *values* (the number of readings queued is
 | |
|     determined by *qsize*) and begins yielding values only when the queue is
 | |
|     full. For example, to "cascade" values along a sequence of LEDs::
 | |
| 
 | |
|         from gpiozero import LEDBoard, Button, queued
 | |
|         from signal import pause
 | |
| 
 | |
|         leds = LEDBoard(5, 6, 13, 19, 26)
 | |
|         btn = Button(17)
 | |
|         for i in range(4):
 | |
|             leds[i].source = queued(leds[i + 1].values, 5)
 | |
|             leds[i].source_delay = 0.01
 | |
|         leds[4].source = btn.values
 | |
|         pause()
 | |
|     """
 | |
|     q = []
 | |
|     it = iter(values)
 | |
|     for i in range(qsize):
 | |
|         q.append(next(it))
 | |
|     for i in cycle(range(qsize)):
 | |
|         yield q[i]
 | |
|         try:
 | |
|             q[i] = next(it)
 | |
|         except StopIteration:
 | |
|             break
 | |
| 
 | |
| 
 | |
| def pre_delayed(values, delay):
 | |
|     """
 | |
|     Waits for *delay* seconds before returning each item from *values*.
 | |
|     """
 | |
|     for v in values:
 | |
|         sleep(delay)
 | |
|         yield v
 | |
| 
 | |
| 
 | |
| def post_delayed(values, delay):
 | |
|     """
 | |
|     Waits for *delay* seconds after returning each item from *values*.
 | |
|     """
 | |
|     for v in values:
 | |
|         yield v
 | |
|         sleep(delay)
 | |
| 
 | |
| 
 | |
| def random_values():
 | |
|     """
 | |
|     Provides an infinite source of random values between 0 and 1. For example,
 | |
|     to produce a "flickering candle" effect with an LED::
 | |
| 
 | |
|         from gpiozero import PWMLED, random_values
 | |
|         from signal import pause
 | |
| 
 | |
|         led = PWMLED(4)
 | |
|         led.source = random_values()
 | |
|         pause()
 | |
| 
 | |
|     If you require a wider range than 0 to 1, see :func:`scaled`.
 | |
|     """
 | |
|     while True:
 | |
|         yield random()
 | |
| 
 | |
| 
 | |
| def sin_values():
 | |
|     """
 | |
|     Provides an infinite source of values representing a sine wave (from -1 to
 | |
|     +1), calculated as the result of applying sign to a simple degrees counter
 | |
|     that increments by one for each requested value. For example, to produce a
 | |
|     "siren" effect with a couple of LEDs::
 | |
| 
 | |
|         from gpiozero import PWMLED, sin_values, scaled, inverted
 | |
|         from signal import pause
 | |
| 
 | |
|         red = PWMLED(2)
 | |
|         blue = PWMLED(3)
 | |
|         red.source_delay = 0.1
 | |
|         blue.source_delay = 0.1
 | |
|         red.source = scaled(sin_values(), 0, 1, -1, 1)
 | |
|         blue.source = inverted(red.values)
 | |
|         pause()
 | |
| 
 | |
|     If you require a wider range than 0 to 1, see :func:`scaled`.
 | |
|     """
 | |
|     for d in cycle(range(360)):
 | |
|         yield sin(radians(d))
 | |
| 
 | |
| 
 | |
| def cos_values():
 | |
|     """
 | |
|     Provides an infinite source of values representing a cosine wave (from -1
 | |
|     to +1), calculated as the result of applying sign to a simple degrees
 | |
|     counter that increments by one for each requested value. For example, to
 | |
|     produce a "siren" effect with a couple of LEDs::
 | |
| 
 | |
|         from gpiozero import PWMLED, cos_values, scaled, inverted
 | |
|         from signal import pause
 | |
| 
 | |
|         red = PWMLED(2)
 | |
|         blue = PWMLED(3)
 | |
|         red.source = scaled(cos_values(), 0, 1, -1, 1)
 | |
|         blue.source = inverted(red.values)
 | |
|         pause()
 | |
| 
 | |
|     If you require a wider range than 0 to 1, see :func:`scaled`.
 | |
|     """
 | |
|     for d in cycle(range(360)):
 | |
|         yield cos(radians(d))
 | |
| 
 |