Last minute changes for 1.2

Warnings about non-physical pins, and period specification for
sin/cosine waves in tools
This commit is contained in:
Dave Jones
2016-04-10 19:29:46 +01:00
parent e2b8171bbb
commit f82ddad1fc
10 changed files with 88 additions and 31 deletions

View File

@@ -5,7 +5,7 @@ Changelog
.. currentmodule:: gpiozero .. currentmodule:: gpiozero
Release 1.2.0 (2016-04-??) Release 1.2.0 (2016-04-10)
========================== ==========================
* Added :class:`Energenie` class for controlling Energenie plugs (`#69`_) * Added :class:`Energenie` class for controlling Energenie plugs (`#69`_)
@@ -32,7 +32,16 @@ Release 1.2.0 (2016-04-??)
And I'll just add a note of thanks to the many people in the community who And I'll just add a note of thanks to the many people in the community who
contributed to this release: we've had some great PRs, suggestions, and bug contributed to this release: we've had some great PRs, suggestions, and bug
reports in this version - keep 'em coming! reports in this version. Of particular note:
* Schelto van Doorn was instrumental in adding support for numerous ADC chips
* Alex Eames generously donated a RasPiO Analog board which was extremely
useful in developing the software SPI interface (and testing the ADC support)
* Andrew Scheller squashed several dozen bugs (usually a day or so after Dave
had introduced them ;)
As always, many thanks to the whole community - we look forward to hearing from
you more in 1.3!
.. _#69: https://github.com/RPi-Distro/python-gpiozero/issues/69 .. _#69: https://github.com/RPi-Distro/python-gpiozero/issues/69
.. _#109: https://github.com/RPi-Distro/python-gpiozero/issues/109 .. _#109: https://github.com/RPi-Distro/python-gpiozero/issues/109

View File

@@ -51,6 +51,8 @@ from .exc import (
GPIOZeroWarning, GPIOZeroWarning,
SPIWarning, SPIWarning,
SPISoftwareFallback, SPISoftwareFallback,
PinWarning,
PinNonPhysical,
) )
from .devices import ( from .devices import (
Device, Device,

View File

@@ -121,3 +121,9 @@ class SPIWarning(GPIOZeroWarning):
class SPISoftwareFallback(SPIWarning): class SPISoftwareFallback(SPIWarning):
"Warning raised when falling back to the software implementation" "Warning raised when falling back to the software implementation"
class PinWarning(GPIOZeroWarning):
"Base class for warnings related to pin implementations"
class PinNonPhysical(PinWarning):
"Warning raised when a non-physical pin is specified in a constructor"

View File

@@ -322,6 +322,7 @@ class HoldMixin(EventsMixin):
``True``) at internals defined by :attr:`hold_time`. ``True``) at internals defined by :attr:`hold_time`.
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self._hold_thread = None
super(HoldMixin, self).__init__(*args, **kwargs) super(HoldMixin, self).__init__(*args, **kwargs)
self._when_held = None self._when_held = None
self._held_from = None self._held_from = None

View File

@@ -261,11 +261,11 @@ PI_REVISIONS = {
'0013': ('B+', '1.2', '2015Q1', 'BCM2835', 'Egoman', 512, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, ), '0013': ('B+', '1.2', '2015Q1', 'BCM2835', 'Egoman', 512, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, ),
'0014': ('CM', '1.1', '2014Q2', 'BCM2835', 'Sony', 512, 'eMMC', 0, 0, False, False, 2, 2, {'SODIMM': CM_SODIMM}, ), '0014': ('CM', '1.1', '2014Q2', 'BCM2835', 'Sony', 512, 'eMMC', 0, 0, False, False, 2, 2, {'SODIMM': CM_SODIMM}, ),
'0015': ('A+', '1.1', '2014Q4', 'BCM2835', 'Sony', 256, 'MicroSD', 1, 0, False, False, 1, 1, {'P1': PLUS_P1}, ), '0015': ('A+', '1.1', '2014Q4', 'BCM2835', 'Sony', 256, 'MicroSD', 1, 0, False, False, 1, 1, {'P1': PLUS_P1}, ),
#'a01041': ('2B', '1.1', '2015Q1', 'BCM2836', 'Sony', 1024, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, ), 'a01041': ('2B', '1.1', '2015Q1', 'BCM2836', 'Sony', 1024, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, ),
#'a21041': ('2B', '1.1', '2015Q1', 'BCM2836', 'Embest', 1024, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, ), 'a21041': ('2B', '1.1', '2015Q1', 'BCM2836', 'Embest', 1024, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, ),
#'900092': ('Zero', '1.2', '2015Q4', 'BCM2835', 'Sony', 512, 'MicroSD', 1, 0, False, False, 0, 0, {'P1': PLUS_P1}, ), '900092': ('Zero', '1.2', '2015Q4', 'BCM2835', 'Sony', 512, 'MicroSD', 1, 0, False, False, 0, 0, {'P1': PLUS_P1}, ),
#'a02082': ('3B', '1.2', '2016Q1', 'BCM2837', 'Sony', 1024, 'MicroSD', 4, 1, True, True, 1, 1, {'P1': PLUS_P1}, ), 'a02082': ('3B', '1.2', '2016Q1', 'BCM2837', 'Sony', 1024, 'MicroSD', 4, 1, True, True, 1, 1, {'P1': PLUS_P1}, ),
#'a22082': ('3B', '1.2', '2016Q1', 'BCM2837', 'Embest', 1024, 'MicroSD', 4, 1, True, True, 1, 1, {'P1': PLUS_P1}, ), 'a22082': ('3B', '1.2', '2016Q1', 'BCM2837', 'Embest', 1024, 'MicroSD', 4, 1, True, True, 1, 1, {'P1': PLUS_P1}, ),
} }
@@ -479,8 +479,12 @@ class PiBoardInfo(namedtuple('PiBoardInfo', (
The pin function you wish to determine pull-up for. Usually this is The pin function you wish to determine pull-up for. Usually this is
something like "GPIO9" for Broadcom GPIO pin 9. something like "GPIO9" for Broadcom GPIO pin 9.
""" """
header, number = self.physical_pin(function) try:
return self.headers[header][number].pull_up header, number = self.physical_pin(function)
except PinNoPins:
return False
else:
return self.headers[header][number].pull_up
_PI_REVISION = None _PI_REVISION = None

View File

@@ -12,6 +12,7 @@ import os
import mmap import mmap
import errno import errno
import struct import struct
import warnings
from time import sleep from time import sleep
from threading import Thread, Event, Lock from threading import Thread, Event, Lock
from collections import Counter from collections import Counter
@@ -24,6 +25,8 @@ from ..exc import (
PinInvalidFunction, PinInvalidFunction,
PinFixedPull, PinFixedPull,
PinSetInput, PinSetInput,
PinNonPhysical,
PinNoPins,
) )
@@ -213,7 +216,12 @@ class NativePin(Pin):
return cls._PINS[number] return cls._PINS[number]
except KeyError: except KeyError:
self = super(NativePin, cls).__new__(cls) self = super(NativePin, cls).__new__(cls)
cls._PINS[number] = self try:
cls.PI_INFO.physical_pin('GPIO%d' % number)
except PinNoPins:
warnings.warn(
PinNonPhysical(
'no physical pins exist for GPIO%d' % number))
self._number = number self._number = number
self._func_offset = self._MEM.GPFSEL_OFFSET + (number // 10) self._func_offset = self._MEM.GPFSEL_OFFSET + (number // 10)
self._func_shift = (number % 10) * 3 self._func_shift = (number % 10) * 3
@@ -238,6 +246,7 @@ class NativePin(Pin):
self.pull = 'up' if cls.PI_INFO.pulled_up('GPIO%d' % number) else 'floating' self.pull = 'up' if cls.PI_INFO.pulled_up('GPIO%d' % number) else 'floating'
self.bounce = None self.bounce = None
self.edges = 'both' self.edges = 'both'
cls._PINS[number] = self
return self return self
def __repr__(self): def __repr__(self):

View File

@@ -6,6 +6,7 @@ from __future__ import (
) )
str = type('') str = type('')
import warnings
import pigpio import pigpio
from . import Pin from . import Pin
@@ -17,6 +18,8 @@ from ..exc import (
PinInvalidPull, PinInvalidPull,
PinInvalidBounce, PinInvalidBounce,
PinInvalidState, PinInvalidState,
PinNonPhysical,
PinNoPins,
) )
@@ -107,12 +110,17 @@ class PiGPIOPin(Pin):
return cls._PINS[(host, port, number)] return cls._PINS[(host, port, number)]
except KeyError: except KeyError:
self = super(PiGPIOPin, cls).__new__(cls) self = super(PiGPIOPin, cls).__new__(cls)
cls._PINS[(host, port, number)] = self
try: try:
self._connection = cls._CONNECTIONS[(host, port)] self._connection = cls._CONNECTIONS[(host, port)]
except KeyError: except KeyError:
self._connection = pigpio.pi(host, port) self._connection = pigpio.pi(host, port)
cls._CONNECTIONS[(host, port)] = self._connection cls._CONNECTIONS[(host, port)] = self._connection
try:
cls.PI_INFO.physical_pin('GPIO%d' % number)
except PinNoPins:
warnings.warn(
PinNonPhysical(
'no physical pins exist for GPIO%d' % number))
self._host = host self._host = host
self._port = port self._port = port
self._number = number self._number = number
@@ -125,11 +133,11 @@ class PiGPIOPin(Pin):
try: try:
self._connection.set_mode(self._number, pigpio.INPUT) self._connection.set_mode(self._number, pigpio.INPUT)
except pigpio.error as e: except pigpio.error as e:
del cls._PINS[(host, port, number)]
raise ValueError(e) raise ValueError(e)
self._connection.set_pull_up_down(self._number, self.GPIO_PULL_UPS[self._pull]) self._connection.set_pull_up_down(self._number, self.GPIO_PULL_UPS[self._pull])
self._connection.set_glitch_filter(self._number, 0) self._connection.set_glitch_filter(self._number, 0)
self._connection.set_PWM_range(self._number, 255) self._connection.set_PWM_range(self._number, 255)
cls._PINS[(host, port, number)] = self
return self return self
def __repr__(self): def __repr__(self):

View File

@@ -6,6 +6,7 @@ from __future__ import (
) )
str = type('') str = type('')
import warnings
from RPi import GPIO from RPi import GPIO
from . import Pin from . import Pin
@@ -18,6 +19,8 @@ from ..exc import (
PinInvalidState, PinInvalidState,
PinInvalidBounce, PinInvalidBounce,
PinPWMFixedValue, PinPWMFixedValue,
PinNonPhysical,
PinNoPins,
) )
@@ -84,7 +87,12 @@ class RPiGPIOPin(Pin):
return cls._PINS[number] return cls._PINS[number]
except KeyError: except KeyError:
self = super(RPiGPIOPin, cls).__new__(cls) self = super(RPiGPIOPin, cls).__new__(cls)
cls._PINS[number] = self try:
cls.PI_INFO.physical_pin('GPIO%d' % number)
except PinNoPins:
warnings.warn(
PinNonPhysical(
'no physical pins exist for GPIO%d' % number))
self._number = number self._number = number
self._pull = 'up' if cls.PI_INFO.pulled_up('GPIO%d' % number) else 'floating' self._pull = 'up' if cls.PI_INFO.pulled_up('GPIO%d' % number) else 'floating'
self._pwm = None self._pwm = None
@@ -94,6 +102,7 @@ class RPiGPIOPin(Pin):
self._when_changed = None self._when_changed = None
self._edges = GPIO.BOTH self._edges = GPIO.BOTH
GPIO.setup(self._number, GPIO.IN, self.GPIO_PULL_UPS[self._pull]) GPIO.setup(self._number, GPIO.IN, self.GPIO_PULL_UPS[self._pull])
cls._PINS[number] = self
return self return self
def __repr__(self): def __repr__(self):

View File

@@ -7,6 +7,7 @@ from __future__ import (
str = type('') str = type('')
import warnings
import RPIO import RPIO
import RPIO.PWM import RPIO.PWM
from RPIO.Exceptions import InvalidChannelException from RPIO.Exceptions import InvalidChannelException
@@ -21,6 +22,8 @@ from ..exc import (
PinInvalidBounce, PinInvalidBounce,
PinInvalidState, PinInvalidState,
PinPWMError, PinPWMError,
PinNonPhysical,
PinNoPins,
) )
@@ -81,7 +84,12 @@ class RPIOPin(Pin):
return cls._PINS[number] return cls._PINS[number]
except KeyError: except KeyError:
self = super(RPIOPin, cls).__new__(cls) self = super(RPIOPin, cls).__new__(cls)
cls._PINS[number] = self try:
cls.PI_INFO.physical_pin('GPIO%d' % number)
except PinNoPins:
warnings.warn(
PinNonPhysical(
'no physical pins exist for GPIO%d' % number))
self._number = number self._number = number
self._pull = 'up' if cls.PI_INFO.pulled_up('GPIO%d' % number) else 'floating' self._pull = 'up' if cls.PI_INFO.pulled_up('GPIO%d' % number) else 'floating'
self._pwm = False self._pwm = False
@@ -93,6 +101,7 @@ class RPIOPin(Pin):
RPIO.setup(self._number, RPIO.IN, self.GPIO_PULL_UPS[self._pull]) RPIO.setup(self._number, RPIO.IN, self.GPIO_PULL_UPS[self._pull])
except InvalidChannelException as e: except InvalidChannelException as e:
raise ValueError(e) raise ValueError(e)
cls._PINS[number] = self
return self return self
def __repr__(self): def __repr__(self):

View File

@@ -16,7 +16,7 @@ try:
except ImportError: except ImportError:
pass pass
from itertools import cycle from itertools import cycle
from math import sin, cos, radians from math import sin, cos, pi
try: try:
from statistics import mean from statistics import mean
except ImportError: except ImportError:
@@ -285,12 +285,11 @@ def random_values():
yield random() yield random()
def sin_values(): def sin_values(period=360):
""" """
Provides an infinite source of values representing a sine wave (from -1 to 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 +1) which repeats every *period* values. For example, to produce a "siren"
that increments by one for each requested value. For example, to produce a effect with a couple of LEDs that repeats once a second::
"siren" effect with a couple of LEDs::
from gpiozero import PWMLED from gpiozero import PWMLED
from gpiozero.tools import sin_values, scaled, inverted from gpiozero.tools import sin_values, scaled, inverted
@@ -300,22 +299,22 @@ def sin_values():
blue = PWMLED(3) blue = PWMLED(3)
red.source_delay = 0.01 red.source_delay = 0.01
blue.source_delay = 0.01 blue.source_delay = 0.01
red.source = scaled(sin_values(), 0, 1, -1, 1) red.source = scaled(sin_values(100), 0, 1, -1, 1)
blue.source = inverted(red.values) blue.source = inverted(red.values)
pause() pause()
If you require a wider range than 0 to 1, see :func:`scaled`. If you require a different range than -1 to +1, see :func:`scaled`.
""" """
for d in cycle(range(360)): angles = (2 * pi * i / period for i in range(period))
yield sin(radians(d)) for a in cycle(angles):
yield sin(a)
def cos_values(): def cos_values(period=360):
""" """
Provides an infinite source of values representing a cosine wave (from -1 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 to +1) which repeats every *period* values. For example, to produce a
counter that increments by one for each requested value. For example, to "siren" effect with a couple of LEDs that repeats once a second::
produce a "siren" effect with a couple of LEDs::
from gpiozero import PWMLED from gpiozero import PWMLED
from gpiozero.tools import cos_values, scaled, inverted from gpiozero.tools import cos_values, scaled, inverted
@@ -325,12 +324,13 @@ def cos_values():
blue = PWMLED(3) blue = PWMLED(3)
red.source_delay = 0.01 red.source_delay = 0.01
blue.source_delay = 0.01 blue.source_delay = 0.01
red.source = scaled(cos_values(), 0, 1, -1, 1) red.source = scaled(cos_values(100), 0, 1, -1, 1)
blue.source = inverted(red.values) blue.source = inverted(red.values)
pause() pause()
If you require a wider range than 0 to 1, see :func:`scaled`. If you require a different range than -1 to +1, see :func:`scaled`.
""" """
for d in cycle(range(360)): angles = (2 * pi * i / period for i in range(period))
yield cos(radians(d)) for a in cycle(angles):
yield cos(a)