From c9461c50d3a2fe346fc10c2166f6a0b46a6f75f8 Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Fri, 29 Apr 2016 12:06:29 +0100 Subject: [PATCH] Add a `pwm` option to the RGBLED and Motor constructors ...along with the other necessary changes required, to allow them to optionally be used with non-PWM-capable pins --- docs/api_output.rst | 4 +- docs/images/composed_devices.dot | 2 + docs/images/composed_devices.pdf | Bin 12376 -> 12641 bytes docs/images/composed_devices.png | Bin 24861 -> 30588 bytes docs/images/composed_devices.svg | 145 ++++++++------- gpiozero/output_devices.py | 75 ++++++-- tests/test_outputs.py | 293 ++++++++++++++++++++++++------- 7 files changed, 378 insertions(+), 141 deletions(-) diff --git a/docs/api_output.rst b/docs/api_output.rst index 1824f11..b6710c2 100644 --- a/docs/api_output.rst +++ b/docs/api_output.rst @@ -28,7 +28,7 @@ PWMLED RGBLED ====== -.. autoclass:: RGBLED(red, green, blue, active_high=True, initial_value=(0, 0, 0)) +.. autoclass:: RGBLED(red, green, blue, active_high=True, initial_value=(0, 0, 0), pwm=True) :members: on, off, toggle, blink, pulse, red, green, blue, is_lit, color Buzzer @@ -40,7 +40,7 @@ Buzzer Motor ===== -.. autoclass:: Motor(forward, backward) +.. autoclass:: Motor(forward, backward, pwm=True) :members: forward, backward, stop Base Classes diff --git a/docs/images/composed_devices.dot b/docs/images/composed_devices.dot index 2a13174..b1611f2 100644 --- a/docs/images/composed_devices.dot +++ b/docs/images/composed_devices.dot @@ -5,6 +5,7 @@ digraph classes { node [shape=rect, style=filled, color="#298029", fontname=Sans, fontcolor="#ffffff", fontsize=10]; edge [arrowhead=onormal, style=dashed]; + RGBLED->LED; RGBLED->PWMLED; LEDBoard->LED; LEDBoard->PWMLED; @@ -16,5 +17,6 @@ digraph classes { TrafficLightsBuzzer->Button; Robot->Motor; + Motor->DigitalOutputDevice; Motor->PWMOutputDevice; } diff --git a/docs/images/composed_devices.pdf b/docs/images/composed_devices.pdf index 8c1805613c688ae1adcfad3b0fa140cfdb366558..f0dfaf8647c1c4bd6828c56ca52e7401d0493337 100644 GIT binary patch delta 7851 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Ⓢ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 literal 24861 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

;l4)Z@GhYNKmV9}4I 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 dze4$gK;{;W@}eHuSa1c - + classes - + RGBLED RGBLED + +LED + +LED + + +RGBLED->LED + + + -PWMLED - -PWMLED +PWMLED + +PWMLED -RGBLED->PWMLED - - +RGBLED->PWMLED + + -LEDBoard - -LEDBoard - - -LEDBoard->PWMLED - - - - -LED - -LED +LEDBoard + +LEDBoard -LEDBoard->LED - - +LEDBoard->LED + + + + +LEDBoard->PWMLED + + LEDBarGraph - -LEDBarGraph - - -LEDBarGraph->PWMLED - - + +LEDBarGraph -LEDBarGraph->LED - - +LEDBarGraph->LED + + + + +LEDBarGraph->PWMLED + + TrafficLightsBuzzer - -TrafficLightsBuzzer + +TrafficLightsBuzzer TrafficLights - -TrafficLights + +TrafficLights -TrafficLightsBuzzer->TrafficLights - - +TrafficLightsBuzzer->TrafficLights + + Buzzer - -Buzzer + +Buzzer -TrafficLightsBuzzer->Buzzer - - +TrafficLightsBuzzer->Buzzer + + Button - -Button + +Button -TrafficLightsBuzzer->Button - - +TrafficLightsBuzzer->Button + + Robot - -Robot + +Robot Motor - -Motor + +Motor -Robot->Motor - - +Robot->Motor + + + + +DigitalOutputDevice + +DigitalOutputDevice + + +Motor->DigitalOutputDevice + + -PWMOutputDevice - -PWMOutputDevice +PWMOutputDevice + +PWMOutputDevice -Motor->PWMOutputDevice - - +Motor->PWMOutputDevice + + diff --git a/gpiozero/output_devices.py b/gpiozero/output_devices.py index 5c13956..ecb2a5b 100644 --- a/gpiozero/output_devices.py +++ b/gpiozero/output_devices.py @@ -555,16 +555,22 @@ class RGBLED(SourceMixin, Device): :param bool initial_value: The initial color for the LED. Defaults to black ``(0, 0, 0)``. + + :param bool pwm: + If ``True`` (the default), construct :class:`PWMLED` instances for + each component of the RGBLED. If ``False``, construct regular + :class:`LED` instances, which prevents smooth color graduations. """ def __init__( self, red=None, green=None, blue=None, active_high=True, - initial_value=(0, 0, 0)): + initial_value=(0, 0, 0), pwm=True): self._leds = () self._blink_thread = None if not all([red, green, blue]): raise GPIOPinMissing('red, green, and blue pins must be provided') + LEDClass = PWMLED if pwm else LED super(RGBLED, self).__init__() - self._leds = tuple(PWMLED(pin, active_high) for pin in (red, green, blue)) + self._leds = tuple(LEDClass(pin, active_high) for pin in (red, green, blue)) self.value = initial_value red = _led_property(0) @@ -587,7 +593,8 @@ class RGBLED(SourceMixin, Device): def value(self): """ Represents the color of the LED as an RGB 3-tuple of ``(red, green, - blue)`` where each value is between 0 and 1. + blue)`` where each value is between 0 and 1 if ``pwm`` was ``True`` + when the class was constructed (and only 0 or 1 if not). For example, purple would be ``(1, 0, 1)`` and yellow would be ``(1, 1, 0)``, while orange would be ``(1, 0.5, 0)``. @@ -596,6 +603,12 @@ class RGBLED(SourceMixin, Device): @value.setter def value(self, value): + for component in value: + if not 0 <= component <= 1: + raise OutputDeviceBadValue('each RGB color component must be between 0 and 1') + if isinstance(self._leds[0], LED): + if component not in (0, 1): + raise OutputDeviceBadValue('each RGB color component must be 0 or 1 with non-PWM RGBLEDs') self._stop_blink() self.red, self.green, self.blue = value @@ -647,10 +660,14 @@ class RGBLED(SourceMixin, Device): Number of seconds off. Defaults to 1 second. :param float fade_in_time: - Number of seconds to spend fading in. Defaults to 0. + Number of seconds to spend fading in. Defaults to 0. Must be 0 if + ``pwm`` was ``False`` when the class was constructed + (:exc:`ValueError` will be raised if not). :param float fade_out_time: - Number of seconds to spend fading out. Defaults to 0. + Number of seconds to spend fading out. Defaults to 0. Must be 0 if + ``pwm`` was ``False`` when the class was constructed + (:exc:`ValueError` will be raised if not). :param tuple on_color: The color to use when the LED is "on". Defaults to white. @@ -667,6 +684,11 @@ class RGBLED(SourceMixin, Device): blink is finished (warning: the default value of *n* will result in this method never returning). """ + if isinstance(self._leds[0], LED): + if fade_in_time: + raise ValueError('fade_in_time must be 0 with non-PWM RGBLEDs') + if fade_out_time: + raise ValueError('fade_out_time must be 0 with non-PWM RGBLEDs') self._stop_blink() self._blink_thread = GPIOThread( target=self._blink_device, @@ -782,22 +804,31 @@ class Motor(SourceMixin, CompositeDevice): :param int backward: The GPIO pin that the backward input of the motor driver chip is connected to. + + :param bool pwm: + If ``True`` (the default), construct :class:`PWMOutputDevice` + instances for the motor controller pins, allowing both direction and + variable speed control. If ``False``, construct + :class:`DigitalOutputDevice` instances, allowing only direction + control. """ - def __init__(self, forward=None, backward=None): + def __init__(self, forward=None, backward=None, pwm=True): if not all([forward, backward]): raise GPIOPinMissing( 'forward and backward pins must be provided' ) + PinClass = PWMOutputDevice if pwm else DigitalOutputDevice super(Motor, self).__init__( - forward_device=PWMOutputDevice(forward), - backward_device=PWMOutputDevice(backward), + forward_device=PinClass(forward), + backward_device=PinClass(backward), _order=('forward_device', 'backward_device')) @property def value(self): """ Represents the speed of the motor as a floating point value between -1 - (full speed backward) and 1 (full speed forward). + (full speed backward) and 1 (full speed forward), with 0 representing + stopped. """ return self.forward_device.value - self.backward_device.value @@ -806,9 +837,15 @@ class Motor(SourceMixin, CompositeDevice): if not -1 <= value <= 1: raise OutputDeviceBadValue("Motor value must be between -1 and 1") if value > 0: - self.forward(value) + try: + self.forward(value) + except ValueError as e: + raise OutputDeviceBadValue(e) elif value < 0: - self.backward(-value) + try: + self.backward(-value) + except ValueError as e: + raise OutputDeviceBadValue(e) else: self.stop() @@ -826,8 +863,14 @@ class Motor(SourceMixin, CompositeDevice): :param float speed: The speed at which the motor should turn. Can be any value between - 0 (stopped) and the default 1 (maximum speed). + 0 (stopped) and the default 1 (maximum speed) if ``pwm`` was + ``True`` when the class was constructed (and only 0 or 1 if not). """ + if not 0 <= speed <= 1: + raise ValueError('forward speed must be between 0 and 1') + if isinstance(self.forward_device, DigitalOutputDevice): + if speed not in (0, 1): + raise ValueError('forward speed must be 0 or 1 with non-PWM Motors') self.backward_device.off() self.forward_device.value = speed @@ -837,8 +880,14 @@ class Motor(SourceMixin, CompositeDevice): :param float speed: The speed at which the motor should turn. Can be any value between - 0 (stopped) and the default 1 (maximum speed). + 0 (stopped) and the default 1 (maximum speed) if ``pwm`` was + ``True`` when the class was constructed (and only 0 or 1 if not). """ + if not 0 <= speed <= 1: + raise ValueError('backward speed must be between 0 and 1') + if isinstance(self.backward_device, DigitalOutputDevice): + if speed not in (0, 1): + raise ValueError('backward speed must be 0 or 1 with non-PWM Motors') self.forward_device.off() self.backward_device.value = speed diff --git a/tests/test_outputs.py b/tests/test_outputs.py index 435cf17..444b1d9 100644 --- a/tests/test_outputs.py +++ b/tests/test_outputs.py @@ -378,67 +378,6 @@ def test_output_pwm_pulse_foreground(): (0.04, 0), ]) -@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), - reason='timing is too random on pypy') -def test_output_pwm_pulse_background(): - pin = MockPWMPin(2) - with PWMOutputDevice(pin) as device: - device.pulse(0.2, 0.2, n=2) - device._blink_thread.join() - pin.assert_states_and_times([ - (0.0, 0), - (0.04, 0.2), - (0.04, 0.4), - (0.04, 0.6), - (0.04, 0.8), - (0.04, 1), - (0.04, 0.8), - (0.04, 0.6), - (0.04, 0.4), - (0.04, 0.2), - (0.04, 0), - (0.04, 0.2), - (0.04, 0.4), - (0.04, 0.6), - (0.04, 0.8), - (0.04, 1), - (0.04, 0.8), - (0.04, 0.6), - (0.04, 0.4), - (0.04, 0.2), - (0.04, 0), - ]) - -@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), - reason='timing is too random on pypy') -def test_output_pwm_pulse_foreground(): - pin = MockPWMPin(2) - with PWMOutputDevice(pin) as device: - device.pulse(0.2, 0.2, n=2, background=False) - pin.assert_states_and_times([ - (0.0, 0), - (0.04, 0.2), - (0.04, 0.4), - (0.04, 0.6), - (0.04, 0.8), - (0.04, 1), - (0.04, 0.8), - (0.04, 0.6), - (0.04, 0.4), - (0.04, 0.2), - (0.04, 0), - (0.04, 0.2), - (0.04, 0.4), - (0.04, 0.6), - (0.04, 0.8), - (0.04, 1), - (0.04, 0.8), - (0.04, 0.6), - (0.04, 0.4), - (0.04, 0.2), - (0.04, 0), - ]) - def test_output_pwm_blink_interrupt(): pin = MockPWMPin(2) with PWMOutputDevice(pin) as device: @@ -461,9 +400,47 @@ def test_rgbled_initial_value(): assert isclose(g.state, 0.2) assert isclose(b.state, 0.0) +def test_rgbled_initial_value_nonpwm(): + r, g, b = (MockPin(i) for i in (1, 2, 3)) + with RGBLED(r, g, b, pwm=False, initial_value=(0, 1, 1)) as device: + assert r.state == 0 + assert g.state == 1 + assert b.state == 1 + +def test_rgbled_initial_bad_value(): + r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) + with pytest.raises(ValueError): + RGBLED(r, g, b, initial_value=(0.1, 0.2, 1.2)) + +def test_rgbled_initial_bad_value_nonpwm(): + r, g, b = (MockPin(i) for i in (1, 2, 3)) + with pytest.raises(ValueError): + RGBLED(r, g, b, pwm=False, initial_value=(0.1, 0.2, 0)) + def test_rgbled_value(): r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: + assert isinstance(device._leds[0], PWMLED) + assert isinstance(device._leds[1], PWMLED) + assert isinstance(device._leds[2], PWMLED) + assert not device.is_active + assert device.value == (0, 0, 0) + device.on() + assert device.is_active + assert device.value == (1, 1, 1) + device.off() + assert not device.is_active + assert device.value == (0, 0, 0) + device.value = (0.5, 0.5, 0.5) + assert device.is_active + assert device.value == (0.5, 0.5, 0.5) + +def test_rgbled_value_nonpwm(): + r, g, b = (MockPin(i) for i in (1, 2, 3)) + with RGBLED(r, g, b, pwm=False) as device: + assert isinstance(device._leds[0], LED) + assert isinstance(device._leds[1], LED) + assert isinstance(device._leds[2], LED) assert not device.is_active assert device.value == (0, 0, 0) device.on() @@ -473,6 +450,33 @@ def test_rgbled_value(): assert not device.is_active assert device.value == (0, 0, 0) +def test_rgbled_bad_value(): + r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) + with RGBLED(r, g, b) as device: + with pytest.raises(ValueError): + device.value = (2, 0, 0) + with RGBLED(r, g, b) as device: + with pytest.raises(ValueError): + device.value = (0, -1, 0) + +def test_rgbled_bad_value_nonpwm(): + r, g, b = (MockPin(i) for i in (1, 2, 3)) + with RGBLED(r, g, b, pwm=False) as device: + with pytest.raises(ValueError): + device.value = (2, 0, 0) + with RGBLED(r, g, b, pwm=False) as device: + with pytest.raises(ValueError): + device.value = (0, -1, 0) + with RGBLED(r, g, b, pwm=False) as device: + with pytest.raises(ValueError): + device.value = (0.5, 0, 0) + with RGBLED(r, g, b, pwm=False) as device: + with pytest.raises(ValueError): + device.value = (0, 0.5, 0) + with RGBLED(r, g, b, pwm=False) as device: + with pytest.raises(ValueError): + device.value = (0, 0, 0.5) + def test_rgbled_toggle(): r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: @@ -485,6 +489,18 @@ def test_rgbled_toggle(): assert not device.is_active assert device.value == (0, 0, 0) +def test_rgbled_toggle_nonpwm(): + r, g, b = (MockPin(i) for i in (1, 2, 3)) + with RGBLED(r, g, b, pwm=False) as device: + assert not device.is_active + assert device.value == (0, 0, 0) + device.toggle() + assert device.is_active + assert device.value == (1, 1, 1) + device.toggle() + assert not device.is_active + assert device.value == (0, 0, 0) + @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_blink_background(): @@ -506,6 +522,27 @@ def test_rgbled_blink_background(): g.assert_states_and_times(expected) b.assert_states_and_times(expected) +@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), + reason='timing is too random on pypy') +def test_rgbled_blink_background_nonpwm(): + r, g, b = (MockPin(i) for i in (1, 2, 3)) + with RGBLED(r, g, b, pwm=False) as device: + start = time() + device.blink(0.1, 0.1, n=2) + assert isclose(time() - start, 0, abs_tol=0.05) + device._blink_thread.join() + assert isclose(time() - start, 0.4, abs_tol=0.05) + expected = [ + (0.0, 0), + (0.0, 1), + (0.1, 0), + (0.1, 1), + (0.1, 0) + ] + r.assert_states_and_times(expected) + g.assert_states_and_times(expected) + b.assert_states_and_times(expected) + @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_blink_foreground(): @@ -525,6 +562,25 @@ def test_rgbled_blink_foreground(): g.assert_states_and_times(expected) b.assert_states_and_times(expected) +@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), + reason='timing is too random on pypy') +def test_rgbled_blink_foreground_nonpwm(): + r, g, b = (MockPin(i) for i in (1, 2, 3)) + with RGBLED(r, g, b, pwm=False) as device: + start = time() + device.blink(0.1, 0.1, n=2, background=False) + assert isclose(time() - start, 0.4, abs_tol=0.05) + expected = [ + (0.0, 0), + (0.0, 1), + (0.1, 0), + (0.1, 1), + (0.1, 0) + ] + r.assert_states_and_times(expected) + g.assert_states_and_times(expected) + b.assert_states_and_times(expected) + @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_fade_background(): @@ -562,6 +618,12 @@ def test_rgbled_fade_background(): g.assert_states_and_times(expected) b.assert_states_and_times(expected) +def test_rgbled_fade_background_nonpwm(): + r, g, b = (MockPin(i) for i in (1, 2, 3)) + with RGBLED(r, g, b, pwm=False) as device: + with pytest.raises(ValueError): + device.blink(0, 0, 0.2, 0.2, n=2) + @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_fade_foreground(): @@ -597,6 +659,12 @@ def test_rgbled_fade_foreground(): g.assert_states_and_times(expected) b.assert_states_and_times(expected) +def test_rgbled_fade_foreground_nonpwm(): + r, g, b = (MockPin(i) for i in (1, 2, 3)) + with RGBLED(r, g, b, pwm=False) as device: + with pytest.raises(ValueError): + device.blink(0, 0, 0.2, 0.2, n=2, background=False) + @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_pulse_background(): @@ -634,6 +702,12 @@ def test_rgbled_pulse_background(): g.assert_states_and_times(expected) b.assert_states_and_times(expected) +def test_rgbled_pulse_background_nonpwm(): + r, g, b = (MockPin(i) for i in (1, 2, 3)) + with RGBLED(r, g, b, pwm=False) as device: + with pytest.raises(ValueError): + device.pulse(0.2, 0.2, n=2) + @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_pulse_foreground(): @@ -669,6 +743,12 @@ def test_rgbled_pulse_foreground(): g.assert_states_and_times(expected) b.assert_states_and_times(expected) +def test_rgbled_pulse_foreground_nonpwm(): + r, g, b = (MockPin(i) for i in (1, 2, 3)) + with RGBLED(r, g, b, pwm=False) as device: + with pytest.raises(ValueError): + device.pulse(0.2, 0.2, n=2, background=False) + def test_rgbled_blink_interrupt(): r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: @@ -679,6 +759,16 @@ def test_rgbled_blink_interrupt(): g.assert_states([0, 1, 0]) b.assert_states([0, 1, 0]) +def test_rgbled_blink_interrupt_nonpwm(): + r, g, b = (MockPin(i) for i in (1, 2, 3)) + with RGBLED(r, g, b, pwm=False) as device: + device.blink(1, 0.1) + sleep(0.2) + device.off() # should interrupt while on + r.assert_states([0, 1, 0]) + g.assert_states([0, 1, 0]) + b.assert_states([0, 1, 0]) + def test_rgbled_close(): r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: @@ -688,6 +778,15 @@ def test_rgbled_close(): device.close() assert device.closed +def test_rgbled_close_nonpwm(): + r, g, b = (MockPin(i) for i in (1, 2, 3)) + with RGBLED(r, g, b, pwm=False) as device: + assert not device.closed + device.close() + assert device.closed + device.close() + assert device.closed + def test_motor_missing_pins(): with pytest.raises(ValueError): Motor() @@ -697,7 +796,18 @@ def test_motor_pins(): b = MockPWMPin(2) with Motor(f, b) as device: assert device.forward_device.pin is f + assert isinstance(device.forward_device, PWMOutputDevice) assert device.backward_device.pin is b + assert isinstance(device.backward_device, PWMOutputDevice) + +def test_motor_pins_nonpwm(): + f = MockPin(1) + b = MockPin(2) + with Motor(f, b, pwm=False) as device: + assert device.forward_device.pin is f + assert isinstance(device.forward_device, DigitalOutputDevice) + assert device.backward_device.pin is b + assert isinstance(device.backward_device, DigitalOutputDevice) def test_motor_close(): f = MockPWMPin(1) @@ -710,6 +820,15 @@ def test_motor_close(): device.close() assert device.closed +def test_motor_close_nonpwm(): + f = MockPin(1) + b = MockPin(2) + with Motor(f, b, pwm=False) as device: + device.close() + assert device.closed + assert device.forward_device.pin is None + assert device.backward_device.pin is None + def test_motor_value(): f = MockPWMPin(1) b = MockPWMPin(2) @@ -726,6 +845,27 @@ def test_motor_value(): assert device.is_active assert device.value == 0.5 assert b.state == 0 and f.state == 0.5 + device.value = -0.5 + assert device.is_active + assert device.value == -0.5 + assert b.state == 0.5 and f.state == 0 + device.value = 0 + assert not device.is_active + assert not device.value + assert b.state == 0 and f.state == 0 + +def test_motor_value_nonpwm(): + f = MockPin(1) + b = MockPin(2) + with Motor(f, b, pwm=False) as device: + device.value = -1 + assert device.is_active + assert device.value == -1 + assert b.state == 1 and f.state == 0 + device.value = 1 + assert device.is_active + assert device.value == 1 + assert b.state == 0 and f.state == 1 device.value = 0 assert not device.is_active assert not device.value @@ -735,9 +875,24 @@ def test_motor_bad_value(): f = MockPWMPin(1) b = MockPWMPin(2) with Motor(f, b) as device: + with pytest.raises(ValueError): + device.value = -2 with pytest.raises(ValueError): device.value = 2 +def test_motor_bad_value_nonpwm(): + f = MockPin(1) + b = MockPin(2) + with Motor(f, b, pwm=False) as device: + with pytest.raises(ValueError): + device.value = -2 + with pytest.raises(ValueError): + device.value = 2 + with pytest.raises(ValueError): + device.value = 0.5 + with pytest.raises(ValueError): + device.value = -0.5 + def test_motor_reverse(): f = MockPWMPin(1) b = MockPWMPin(2) @@ -748,4 +903,20 @@ def test_motor_reverse(): device.reverse() assert device.value == -1 assert b.state == 1 and f.state == 0 + device.backward(0.5) + assert device.value == -0.5 + assert b.state == 0.5 and f.state == 0 + device.reverse() + assert device.value == 0.5 + assert b.state == 0 and f.state == 0.5 +def test_motor_reverse_nonpwm(): + f = MockPin(1) + b = MockPin(2) + with Motor(f, b, pwm=False) as device: + device.forward() + assert device.value == 1 + assert b.state == 0 and f.state == 1 + device.reverse() + assert device.value == -1 + assert b.state == 1 and f.state == 0