Skip to content

Commit

Permalink
Merge branch 'energenie-sockets-preserve-state'
Browse files Browse the repository at this point in the history
  • Loading branch information
bennuttall committed Mar 1, 2021
2 parents f66795b + f4fab43 commit 8beee82
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 12 deletions.
17 changes: 11 additions & 6 deletions gpiozero/boards.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
GPIOPinMissing,
EnergenieSocketMissing,
EnergenieBadSocket,
EnergenieBadInitialValue,
OutputDeviceBadValue,
CompositeDeviceBadDevice,
)
Expand Down Expand Up @@ -2063,11 +2062,14 @@ class Energenie(SourceMixin, Device):
Which socket this instance should control. This is an integer number
between 1 and 4.
:param bool initial_value:
:type initial_value: bool or None
:param initial_value:
The initial state of the socket. As Energenie sockets provide no
means of reading their state, you must provide an initial state for
means of reading their state, you may provide an initial state for
the socket, which will be set upon construction. This defaults to
:data:`False` which will switch the socket off.
Specifying :data:`None` will not set any initial state nor transmit any
control signal to the device.
:type pin_factory: Factory or None
:param pin_factory:
Expand All @@ -2081,15 +2083,13 @@ def __init__(self, socket=None, initial_value=False, pin_factory=None):
raise EnergenieSocketMissing('socket number must be provided')
if not (1 <= socket <= 4):
raise EnergenieBadSocket('socket number must be between 1 and 4')
if initial_value is None:
raise EnergenieBadInitialValue("initial value can't be None")
self._value = None
super(Energenie, self).__init__(pin_factory=pin_factory)
self._socket = socket
self._master = _EnergenieMaster(pin_factory=pin_factory)
if initial_value:
self.on()
else:
elif initial_value is not None:
self.off()

def close(self):
Expand Down Expand Up @@ -2120,11 +2120,16 @@ def value(self):
"""
Returns :data:`True` if the socket is on and :data:`False` if the
socket is off. Setting this property changes the state of the socket.
Returns :data:`None` only when constructed with :data:`initial_value`
set to :data:`None` and neither :data:`on()` nor :data:`off()` have
been called since construction.
"""
return self._value

@value.setter
def value(self, value):
if value is None:
raise TypeError('value cannot be None')
value = bool(value)
self._master.transmit(self._socket, value)
self._value = value
Expand Down
3 changes: 0 additions & 3 deletions gpiozero/exc.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,6 @@ class EnergenieSocketMissing(CompositeDeviceError, ValueError):
class EnergenieBadSocket(CompositeDeviceError, ValueError):
"Error raised when an invalid socket number is passed to :class:`Energenie`"

class EnergenieBadInitialValue(CompositeDeviceError, ValueError):
"Error raised when an invalid initial value is passed to :class:`Energenie`"

class SPIError(GPIOZeroError):
"Base class for errors related to the SPI implementation"

Expand Down
25 changes: 22 additions & 3 deletions tests/test_boards.py
Original file line number Diff line number Diff line change
Expand Up @@ -1264,19 +1264,21 @@ def test_energenie_bad_init(mock_factory):
Energenie(0)
with pytest.raises(ValueError):
Energenie(5)
with pytest.raises(ValueError):
Energenie(1, initial_value=None)

def test_energenie(mock_factory):
pins = [mock_factory.pin(n) for n in (17, 22, 23, 27, 24, 25)]
with Energenie(1, initial_value=True) as device1, \
Energenie(2, initial_value=False) as device2:
Energenie(2, initial_value=False) as device2, \
Energenie(3, initial_value=None) as device3:
assert repr(device1) == '<gpiozero.Energenie object on socket 1>'
assert repr(device2) == '<gpiozero.Energenie object on socket 2>'
assert repr(device3) == '<gpiozero.Energenie object on socket 3>'
assert device1.value
assert not device2.value
assert device3.value is None
assert device1.socket == 1
assert device2.socket == 2
assert device3.socket == 3
[pin.clear_states() for pin in pins]
device1.on()
assert device1.value
Expand All @@ -1295,6 +1297,23 @@ def test_energenie(mock_factory):
pins[3].assert_states_and_times([(0.0, True), (0.0, True)])
pins[4].assert_states_and_times([(0.0, False)])
pins[5].assert_states_and_times([(0.0, False), (0.1, True), (0.25, False)])
[pin.clear_states() for pin in pins]
device3.on()
assert device3.value
pins[0].assert_states_and_times([(0.0, False), (0.0, True)])
pins[1].assert_states_and_times([(0.0, True), (0.0, False)])
pins[2].assert_states_and_times([(0.0, True), (0.0, False)])
pins[3].assert_states_and_times([(0.0, True), (0.0, False)])
pins[4].assert_states_and_times([(0.0, False)])
pins[5].assert_states_and_times([(0.0, False), (0.1, True), (0.25, False)])

device3.value = False
assert not device3.value
device3.value = True
assert device3.value
with pytest.raises(TypeError):
device3.value = None

device1.close()
assert repr(device1) == '<gpiozero.Energenie object closed>'

Expand Down

0 comments on commit 8beee82

Please sign in to comment.