diff --git a/gpiozero/boards.py b/gpiozero/boards.py index 4aee89e8..994f3b27 100644 --- a/gpiozero/boards.py +++ b/gpiozero/boards.py @@ -158,16 +158,16 @@ def __init__(self, *args, **kwargs): for name, pin in kwargs.items() }) def get_new_handler(device): - def fire_both_events(ticks): - device._fire_events(ticks) - self._fire_events(ticks) + def fire_both_events(ticks, state): + device._fire_events(ticks, device._state_to_value(state)) + self._fire_events(ticks, self.value) return fire_both_events for button in self: button.pin.when_changed = get_new_handler(button) self._when_changed = None self._last_value = None # Call _fire_events once to set initial state of events - self._fire_events() + self._fire_events(self.pin_factory.ticks(), None) self.hold_time = hold_time self.hold_repeat = hold_repeat @@ -191,10 +191,9 @@ def _fire_changed(self): if self.when_changed: self.when_changed() - def _fire_events(self, ticks): - super(ButtonBoard, self)._fire_events(ticks) - old_value = self._last_value - new_value = self._last_value = self.value + def _fire_events(self, ticks, new_value): + super(ButtonBoard, self)._fire_events(ticks, new_value) + old_value, self._last_value = self._last_value, new_value if old_value is None: # Initial "indeterminate" value; don't do anything pass diff --git a/gpiozero/input_devices.py b/gpiozero/input_devices.py index 3918e57d..043c40fa 100644 --- a/gpiozero/input_devices.py +++ b/gpiozero/input_devices.py @@ -105,13 +105,16 @@ def __init__( try: self.pin.bounce = bounce_time self.pin.edges = 'both' - self.pin.when_changed = self._fire_events + self.pin.when_changed = self._pin_changed # Call _fire_events once to set initial state of events self._fire_events(self.pin_factory.ticks(), None) except: self.close() raise + def _pin_changed(self, ticks, state): + self._fire_events(ticks, self._state_to_value(state)) + class SmoothedInputDevice(EventsMixin, InputDevice): """ diff --git a/gpiozero/mixins.py b/gpiozero/mixins.py index afd06f85..a68b8938 100644 --- a/gpiozero/mixins.py +++ b/gpiozero/mixins.py @@ -165,7 +165,7 @@ def __init__(self, *args, **kwargs): self._inactive_event = Event() self._when_activated = None self._when_deactivated = None - self._last_state = None + self._last_value = None self._last_changed = self.pin_factory.ticks() def wait_for_active(self, timeout=None): @@ -306,21 +306,21 @@ def _fire_deactivated(self): if self.when_deactivated: self.when_deactivated() - def _fire_events(self, ticks, state): - old_state = self._last_state - # NOTE: we are interested in the state of the *device*, not the pin - # (hence why the state parameter is ignored here) - new_state = self._last_state = self.is_active - if old_state is None: + def _fire_events(self, ticks, new_value): + # NOTE: in contrast to the pin when_changed event, this method takes + # ticks and *value* (i.e. the device's .value) as opposed to a pin's + # *state*. + old_value, self._last_value = self._last_value, new_value + if old_value is None: # Initial "indeterminate" state; set events but don't fire # callbacks as there's not necessarily an edge - if new_state: + if new_value: self._active_event.set() else: self._inactive_event.set() - elif old_state != new_state: + elif old_value != new_value: self._last_changed = ticks - if new_state: + if new_value: self._inactive_event.clear() self._active_event.set() self._fire_activated() diff --git a/gpiozero/other_devices.py b/gpiozero/other_devices.py index 039b6d4d..69480e8e 100644 --- a/gpiozero/other_devices.py +++ b/gpiozero/other_devices.py @@ -53,7 +53,7 @@ class PingServer(InternalDevice): def __init__(self, host): self.host = host super(PingServer, self).__init__() - self._fire_events() + self._fire_events(self.pin_factory.ticks(), None) def __repr__(self): return '' % self.host @@ -121,7 +121,7 @@ def __init__(self, sensor_file='/sys/class/thermal/thermal_zone0/temp', self.min_temp = min_temp self.max_temp = max_temp self.threshold = threshold - self._fire_events() + self._fire_events(self.pin_factory.ticks(), None) def __repr__(self): return '' % self.temperature @@ -153,6 +153,7 @@ def is_active(self): """ return self.temperature > self.threshold + class LoadAverage(InternalDevice): """ Extends :class:`InternalDevice` to provide a device which is active when @@ -207,7 +208,7 @@ def __init__(self, load_average_file='/proc/loadavg', min_load_average=0.0, 15: 2, }[minutes] super(LoadAverage, self).__init__() - self._fire_events() + self._fire_events(self.pin_factory.ticks(), None) def __repr__(self): return '' % self.load_average @@ -279,7 +280,7 @@ def __init__(self, start_time, end_time, utc=True): self.start_time = start_time self.end_time = end_time self.utc = utc - self._fire_events() + self._fire_events(self.pin_factory.ticks(), None) def __repr__(self): return '' % ( diff --git a/gpiozero/pins/native.py b/gpiozero/pins/native.py index 384c787f..18ba45ac 100644 --- a/gpiozero/pins/native.py +++ b/gpiozero/pins/native.py @@ -262,7 +262,7 @@ def _run(self, factory, queue): pass else: if ( - pin._last_call is None or pin._bounce is None or + pin._bounce is None or pin._last_call is None or factory.ticks_diff(ticks, pin._last_call) > pin._bounce ): pin._call_when_changed(ticks, state) @@ -448,6 +448,7 @@ def _set_edges(self, value): def _enable_event_detect(self): self.factory.fs.watch(self.number) + self._last_call = None def _disable_event_detect(self): self.factory.fs.unwatch(self.number) diff --git a/gpiozero/pins/pi.py b/gpiozero/pins/pi.py index 5a7dc640..694fe1ed 100644 --- a/gpiozero/pins/pi.py +++ b/gpiozero/pins/pi.py @@ -261,14 +261,14 @@ def _call_when_changed(self, ticks, state): in descendents if additional (currently redundant) parameters need to be passed. """ - method = self.when_changed() + method = self._when_changed() if method is None: self.when_changed = None else: method(ticks, state) def _get_when_changed(self): - return self._when_changed + return None if self._when_changed is None else self._when_changed() def _set_when_changed(self, value): with self._when_changed_lock: