def changed(self, handler, sensitivity=None): self._handler = handler if sensitivity != None: self._sensitivity = sensitivity if self._t_watch == None: self._t_watch = AsyncWorker(self._watch) self._t_watch.start()
def fade(self, start, end, duration): """Fades an LED to a specific brightness over a specific time in seconds @param self Object pointer. @param start Starting brightness % @param end Ending brightness % @param duration Time duration ( in seconds ) of the fade""" self.stop() time_start = time.time() self.pwm(PULSE_FREQUENCY, start) def _fade(): self.fading = True if time.time() - time_start >= duration: self.duty_cycle(end) self.fading = False return False current = (time.time() - time_start) / duration brightness = start + (float(end - start) * current) self.duty_cycle(round(brightness)) time.sleep(1.0 / PULSE_FPS) self.fader = AsyncWorker(_fade) self.fader.start() return True
class AnalogInput(object): type = 'Analog Input' def __init__(self, channel): self.channel = channel self._sensitivity = 0.1 self._t_watch = None self.last_value = None def read(self): return _analog.read_se_adc(self.channel) def sensitivity(self, sensitivity): self._sensitivity = sensitivity def changed(self, handler, sensitivity=None): self._handler = handler if sensitivity != None: self._sensitivity = sensitivity if self._t_watch == None: self._t_watch = AsyncWorker(self._watch) self._t_watch.start() def _watch(self): value = self.read() if self.last_value != None and abs( value - self.last_value) > self._sensitivity: if callable(self._handler): self._handler(self, value) self.last_value = value time.sleep(0.01)
def startup(cycle_interruptor = (lambda ticks, cycles : None), rate=0.1, fade_out=0.2): lights = [exp.light.blue, exp.light.yellow, exp.light.red, exp.light.green] passes = list(islice(cycle([lights, lights[::-1]]), None, 2)) serie = [item for sublist in [passes[0]] + map(lambda p : p[1:], passes[1:]) for item in sublist] ticks = 0 cycles = 0 def _cycler(): global ticks global cycles cycles += 1 for s in serie: ticks += 1 s.fade(100,0,fade_out) sleep(rate) if cycle_interruptor(ticks, cycle): exp.light.off() return False exp.light.off() worker = AsyncWorker(_cycler) worker.start() return True
class AnalogInput(object): type = 'Analog Input' def __init__(self, channel): self.channel = channel self._sensitivity = 0.1 self._t_watch = None self.last_value = None def read(self): return _analog.read_se_adc(self.channel) def sensitivity(self, sensitivity): self._sensitivity = sensitivity def changed(self, handler, sensitivity=None): self._handler = handler if sensitivity != None: self._sensitivity = sensitivity if self._t_watch == None: self._t_watch = AsyncWorker(self._watch) self._t_watch.start() def _watch(self): value = self.read() if self.last_value != None and abs(value-self.last_value) > self._sensitivity: if callable(self._handler): self._handler(self, value) self.last_value = value time.sleep(0.01)
def startup( cycle_interruptor=(lambda ticks, cycles: None), rate=0.1, fade_out=0.2): lights = [exp.light.blue, exp.light.yellow, exp.light.red, exp.light.green] passes = list(islice(cycle([lights, lights[::-1]]), None, 2)) serie = [ item for sublist in [passes[0]] + map(lambda p: p[1:], passes[1:]) for item in sublist ] ticks = 0 cycles = 0 def _cycler(): global ticks global cycles cycles += 1 for s in serie: ticks += 1 s.fade(100, 0, fade_out) sleep(rate) if cycle_interruptor(ticks, cycle): exp.light.off() return False exp.light.off() worker = AsyncWorker(_cycler) worker.start() return True
def set_timeout(self,function,seconds): def fn_timeout(): time.sleep(seconds) function() return False timeout = AsyncWorker(fn_timeout) timeout.start() return True
def set_timeout(function,seconds): def fn_timeout(): time.sleep(seconds) function() return False timeout = AsyncWorker(fn_timeout) timeout.start() return True
def melody(self,notes,duration = 0.5,loop = True): self.stop() time_start = time.time() is_notation = False if notes[0] == 'N': is_notation = True notes.pop(0) if duration <= 0.0001: raise ValueError('Duration must be greater than 0.0001') if len(notes) == 0: raise ValueError('You must provide at least one note') # Get the total length of the tune # so we can play it! total = len(notes) * duration def melody(): now = time.time() - time_start # Play only once if loop is false if loop == False and int(now / total) > 0: self._stop_buzzer() return False # Figure out how far we are into the current iteration # Then divide by duration to find the current note index delta = round( (now % total) / duration ) # Select the note from the notes array note = notes[int(delta)-1] if is_notation: # this note and above would be OVER NINE THOUSAND Hz! # Treat it as an explicit pitch instead if note == 0: self._stop_buzzer() else: pibrella.buzzer.buzz(note) else: if note == '-': self._stop_buzzer() else: # Play the note pibrella.buzzer.note(note) # Sleep a bit time.sleep(0.0001) self._melody = AsyncWorker(melody) self.fps = 100 self._melody.start()
def fade(self, start, end, duration): """Fades an LED to a specific brightness over a specific time in seconds @param self Object pointer. @param start Starting brightness % @param end Ending brightness % @param duration Time duration ( in seconds ) of the fade""" self.stop() time_start = time.time() self.pwm(PULSE_FREQUENCY, start) def _fade(): self.fading = True if time.time() - time_start >= duration: self.duty_cycle(end) self.fading = False return False current = (time.time() - time_start) / duration brightness = start + (float(end-start) * current) self.duty_cycle(round(brightness)) time.sleep(1.0 / PULSE_FPS) self.fader = AsyncWorker(_fade) self.fader.start() return True
def fade(self,start,end,duration): self.stop() time_start = time.time() self.pwm(PULSE_FREQUENCY,start) def _fade(): if time.time() - time_start >= duration: self.duty_cycle(end) return False current = (time.time() - time_start) / duration brightness = start + (float(end-start) * current) self.duty_cycle(round(brightness)) time.sleep(0.1) self.fader = AsyncWorker(_fade) self.fader.start() return True
def async_start(self, name, function): self.workers[name] = AsyncWorker(function) self.workers[name].start() return True
class Buzzer(Output): type = 'Buzzer' def __init__(self, pin): self._melody = None super(Buzzer, self).__init__(pin) def buzz(self, frequency): self.pwm(frequency, 30) # Play a single note, mathmatically # deduced from its index, offset from 440Hz def note(self, note): note = float(note) a = pow(2.0, 1.0 / 12.0) f = 440.00 * pow(a, note) self.buzz(f) return True # Example sound effects def success(self): # Repeat the last note to extend its duration self.melody([0, 1, 2, 3, 3, 3, 3, 3], 0.2, False) return True def fail(self): # Repeat the last note to extend its duration self.melody([5, 4, 3, 2, 1, 1, 1, 1, 1], 0.2, False) return True def melody(self, notes, duration=0.5, loop=True): self.stop() time_start = time.time() is_notation = False if notes[0] == 'N': is_notation = True notes.pop(0) if duration <= 0.0001: raise ValueError('Duration must be greater than 0.0001') if len(notes) == 0: raise ValueError('You must provide at least one note') # Get the total length of the tune # so we can play it! total = len(notes) * duration def melody(): now = time.time() - time_start # Play only once if loop is false if loop == False and int(now / total) > 0: self._stop_buzzer() return False # Figure out how far we are into the current iteration # Then divide by duration to find the current note index delta = round((now % total) / duration) # Select the note from the notes array note = notes[int(delta) - 1] if is_notation: # this note and above would be OVER NINE THOUSAND Hz! # Treat it as an explicit pitch instead if note == 0: self._stop_buzzer() else: pibrella.buzzer.buzz(note) else: if note == '-': self._stop_buzzer() else: # Play the note pibrella.buzzer.note(note) # Sleep a bit time.sleep(0.0001) self._melody = AsyncWorker(melody) self.fps = 100 self._melody.start() def alarm(self): # Play all notes from -30 to 30 # with a note duration of 0.01sec # and, boom, we have an alarm! self.melody(range(-30, 30), 0.01) def notes(self, notation, speed=0.5): import re # Constant of about 1.0594 N = pow(2.0, (1.0 / 12.0)) # Table of notes, no support for flats YET note_key = [ 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#' ] # Split our notation into individual notes notes = notation.split(' ') # print notes # Set up a list for our parsed output parsed = ['N'] # Step through each note in turn for note in notes: # Split out the note and duration components detail = note.split(':') if len(detail) == 2: # We have a note and a duration note = detail[0] dur = int(detail[1]) else: # We have just a note, so duration is 1 beat note = detail[0] dur = 1 # Now try to match an octave octave = re.findall(r'\d+', note) # If we can't find one, default to octave 5 if len(octave) == 0: octave = 5.0 else: note = note.replace(octave[0], '') octave = float(octave[0]) # If the note is a rest, turn off for that duration if note == 'R': for _ in range(dur): parsed.append(0) # Frequency of 0 ( off ) else: # Otherwise, calculate the pitch of the note from A1 at 55Hz note_index = float(note_key.index(note)) # Pitch of the note itself is 1.0594 ^ note_index pitch = 55.000 * pow(N, note_index) # Then we shift up 2 to the power of the octave index -1 pitch = round(pitch * pow(2, (octave - 1)), 3) for _ in range(dur): parsed.append(pitch) self.melody(parsed, speed) def _stop_buzzer(self): self.duty_cycle(100) self.gpio_pwm.stop() time.sleep(0.02) GPIO.output(self.pin, 0) def stop(self): if self._melody != None: self._melody.stop() self._stop_buzzer() return super(Buzzer, self).stop()
class Output(Pin): type = 'Output' def __init__(self, pin): GPIO.setup(pin, GPIO.OUT, initial=0) super(Output, self).__init__(pin) self.gpio_pwm = GPIO.PWM(pin, 1) self.pulser = Pulse(self, 0, 0, 0, 0) self.blinking = False self.pulsing = False self.fader = None ## Fades an LED to a specific brightness over a specific time def fade(self, start, end, duration): self.stop() time_start = time.time() self.pwm(PULSE_FREQUENCY, start) def _fade(): if time.time() - time_start >= duration: self.duty_cycle(end) return False current = (time.time() - time_start) / duration brightness = start + (float(end - start) * current) self.duty_cycle(round(brightness)) time.sleep(0.1) self.fader = AsyncWorker(_fade) self.fader.start() return True ## Blinks an LED by working out the correct PWM frequency/duty cycle # @param self Object pointer. # @param on Time the LED should stay at 100%/on # @param off Time the LED should stay at 0%/off def blink(self, on=1, off=-1): if off == -1: off = on off = float(off) on = float(on) total = off + on duty_cycle = 100.0 * (on / total) # Stop the thread that's pulsing the LED if self.pulsing: self.stop_pulse() # Use pure PWM blinking, because threads are fugly if self.blinking: self.frequency(1.0 / total) self.duty_cycle(duty_cycle) else: self.pwm(1.0 / total, duty_cycle) self.blinking = True return True ## Pulses an LED # @param self Object pointer. # @param transition_on Time the transition from 0% to 100% brightness should take # @param transition_off Time the trantition from 100% to 0% brightness should take # @param time_on Time the LED should stay at 100% brightness # @param time_off Time the LED should stay at 0% brightness def pulse(self, transition_on=None, transition_off=None, time_on=None, time_off=None): # This needs a thread to handle the fade in and out # Attempt to cascade parameters # pulse() = pulse(0.5,0.5,0.5,0.5) # pulse(0.5,1.0) = pulse(0.5,1.0,0.5,0.5) # pulse(0.5,1.0,1.0) = pulse(0.5,1.0,1.0,1.0) # pulse(0.5,1.0,1.0,0.5) = - if transition_on == None: transition_on = 0.5 if transition_off == None: transition_off = transition_on if time_on == None: time_on = transition_on if time_off == None: time_off = transition_on # Fire up PWM if it's not running if self.blinking == False: self.pwm(PULSE_FREQUENCY, 0.0) # pulse(x,y,0,0) is basically just a regular blink # only fire up a thread if we really need it if transition_on == 0 and transition_off == 0: self.blink(time_on, time_off) else: self.pulser.time_on = time_on self.pulser.time_off = time_off self.pulser.transition_on = transition_on self.pulser.transition_off = transition_off self.pulser.start() # Kick off the pulse thread self.pulsing = True self.blinking = True return True def pwm(self, freq, duty_cycle=50): self.gpio_pwm.ChangeDutyCycle(duty_cycle) self.gpio_pwm.ChangeFrequency(freq) self.gpio_pwm.start(duty_cycle) return True def frequency(self, freq): self.gpio_pwm.ChangeFrequency(freq) return True def duty_cycle(self, duty_cycle): self.gpio_pwm.ChangeDutyCycle(duty_cycle) return True ## Stops the pulsing thread def stop(self): if self.fader != None: self.fader.stop() self.blinking = False self.stop_pulse() # Abruptly stopping PWM is a bad idea # unless we're writing a 1 or 0 # So don't inherit the parent classes # stop() since weird bugs happen # Threaded PWM access was aborting with # no errors when stop coincided with a # duty cycle change. return True ## Stops the pulsing thread # @param self Object pointer. def stop_pulse(self): self.pulsing = False self.pulser.stop() self.pulser = Pulse(self, 0, 0, 0, 0) def write(self, value): blinking = self.blinking self.stop() self.duty_cycle(100) self.gpio_pwm.stop() # Some gymnastics here to fix a bug ( in RPi.GPIO?) # That occurs when trying to output(1) immediately # after stopping the PWM # A small delay is needed. Ugly, but it works if blinking and value == 1: time.sleep(0.02) GPIO.output(self.pin, value) return True ## Turns an Output on # @param self Object pointer. # # Includes handling of pulsing/blinking functions # which must be stopped before turning on def on(self): self.write(1) return True ## Turns an Output off # @param self Object pointer. # # Includes handling of pulsing/blinking functions # which must be stopped before turning off def off(self): self.write(0) return True # Alias on/off to conventional names high = on low = off def toggle(self): if (self.blinking): self.write(0) return True if (self.read() == 1): self.write(0) else: self.write(1) return True
class Buzzer(Output): type = 'Buzzer' def __init__(self,pin): self._melody = None super(Buzzer,self).__init__(pin) def buzz(self,frequency): self.pwm(frequency,30) # Play a single note, mathmatically # deduced from its index, offset from 440Hz def note(self,note): note = float(note) a = pow(2.0, 1.0/12.0) f = 440.00 * pow(a,note) self.buzz(f) return True # Example sound effects def success(self): # Repeat the last note to extend its duration self.melody([0,1,2,3,3,3,3,3],0.2,False) return True def fail(self): # Repeat the last note to extend its duration self.melody([5,4,3,2,1,1,1,1,1],0.2,False) return True def melody(self,notes,duration = 0.5,loop = True): self.stop() time_start = time.time() is_notation = False if notes[0] == 'N': is_notation = True notes.pop(0) if duration <= 0.0001: raise ValueError('Duration must be greater than 0.0001') if len(notes) == 0: raise ValueError('You must provide at least one note') # Get the total length of the tune # so we can play it! total = len(notes) * duration def melody(): now = time.time() - time_start # Play only once if loop is false if loop == False and int(now / total) > 0: self._stop_buzzer() return False # Figure out how far we are into the current iteration # Then divide by duration to find the current note index delta = round( (now % total) / duration ) # Select the note from the notes array note = notes[int(delta)-1] if is_notation: # this note and above would be OVER NINE THOUSAND Hz! # Treat it as an explicit pitch instead if note == 0: self._stop_buzzer() else: pibrella.buzzer.buzz(note) else: if note == '-': self._stop_buzzer() else: # Play the note pibrella.buzzer.note(note) # Sleep a bit time.sleep(0.0001) self._melody = AsyncWorker(melody) self.fps = 100 self._melody.start() def alarm(self): # Play all notes from -30 to 30 # with a note duration of 0.01sec # and, boom, we have an alarm! self.melody(range(-30,30),0.01) def notes(self,notation,speed=0.5): import re # Constant of about 1.0594 N = pow( 2.0, (1.0/12.0) ) # Table of notes, no support for flats YET note_key = ['A','A#','B','C','C#','D','D#','E','F','F#','G','G#'] # Split our notation into individual notes notes = notation.split(' ') # print notes # Set up a list for our parsed output parsed = ['N'] # Step through each note in turn for note in notes: # Split out the note and duration components detail = note.split(':') if len(detail) == 2: # We have a note and a duration note = detail[0] dur = int(detail[1]) else: # We have just a note, so duration is 1 beat note = detail[0] dur = 1 # Now try to match an octave octave = re.findall(r'\d+', note) # If we can't find one, default to octave 5 if len(octave) == 0: octave = 5.0 else: note = note.replace(octave[0],'') octave = float(octave[0]) # If the note is a rest, turn off for that duration if note == 'R': for _ in range(dur): parsed.append(0) # Frequency of 0 ( off ) else: # Otherwise, calculate the pitch of the note from A1 at 55Hz note_index = float(note_key.index( note )) # Pitch of the note itself is 1.0594 ^ note_index pitch = 55.000 * pow( N, note_index ) # Then we shift up 2 to the power of the octave index -1 pitch = round( pitch * pow( 2, ( octave - 1 ) ) ,3) for _ in range(dur): parsed.append(pitch) self.melody(parsed,speed) def _stop_buzzer(self): self.duty_cycle(100) self.gpio_pwm.stop() time.sleep(0.02) GPIO.output(self.pin,0) def stop(self): if self._melody != None: self._melody.stop() self._stop_buzzer() return super(Buzzer,self).stop()
class Output(Pin): """ExplorerHAT class representing a GPIO Output Output contains methods that apply only to outputs. It also contains methods for pulsing, blinking LEDs or other attached devices""" type = 'Output' def __init__(self, pin): GPIO.setup(pin, GPIO.OUT, initial=0) super(Output, self).__init__(pin) self.gpio_pwm = GPIO.PWM(pin, PULSE_FREQUENCY) self.gpio_pwm.start(0) self.pulser = Pulse(self, 0, 0, 0, 0) self.blinking = False self.pulsing = False self.fading = False self.fader = None self._value = 0 def __del__(self): self.gpio_pwm.stop() Pin.__del__(self) def fade(self, start, end, duration): """Fades an LED to a specific brightness over a specific time in seconds @param self Object pointer. @param start Starting brightness % @param end Ending brightness % @param duration Time duration ( in seconds ) of the fade""" self.stop() time_start = time.time() self.pwm(PULSE_FREQUENCY, start) def _fade(): self.fading = True if time.time() - time_start >= duration: self.duty_cycle(end) self.fading = False return False current = (time.time() - time_start) / duration brightness = start + (float(end - start) * current) self.duty_cycle(round(brightness)) time.sleep(1.0 / PULSE_FPS) self.fader = AsyncWorker(_fade) self.fader.start() return True def blink(self, on=1, off=-1): """Blinks an LED by working out the correct PWM frequency/duty cycle @param self Object pointer. @param on Time the LED should stay at 100%/on @param off Time the LED should stay at 0%/off""" self.stop() if off == -1: off = on off = float(off) on = float(on) total = off + on duty_cycle = 100.0 * (on / total) # Use pure PWM blinking, because threads are ugly self.frequency(1.0 / total) self.duty_cycle(duty_cycle) self.blinking = True return True def pulse(self, transition_on=None, transition_off=None, time_on=None, time_off=None): """Pulses an LED @param self Object pointer. @param transition_on Time the transition from 0% to 100% brightness should take @param transition_off Time the trantition from 100% to 0% brightness should take @param time_on Time the LED should stay at 100% brightness @param time_off Time the LED should stay at 0% brightness""" self.stop() # This needs a thread to handle the fade in and out # Attempt to cascade parameters # pulse() = pulse(0.5,0.5,0.5,0.5) # pulse(0.5,1.0) = pulse(0.5,1.0,0.5,0.5) # pulse(0.5,1.0,1.0) = pulse(0.5,1.0,1.0,1.0) # pulse(0.5,1.0,1.0,0.5) = - if transition_on is None: transition_on = 0.5 if transition_off is None: transition_off = transition_on if time_on is None: time_on = transition_on if time_off is None: time_off = transition_on # pulse(x,y,0,0) is basically just a regular blink # only fire up a thread if we really need it if transition_on == 0 and transition_off == 0: self.blink(time_on, time_off) self.blinking = True else: self.pulser.time_on = time_on self.pulser.time_off = time_off self.pulser.transition_on = transition_on self.pulser.transition_off = transition_off self.pulser.start() self.pulsing = True return True def pwm(self, freq, duty_cycle=50): self.gpio_pwm.ChangeDutyCycle(duty_cycle) self.gpio_pwm.ChangeFrequency(freq) #self.gpio_pwm.start(duty_cycle) return True def frequency(self, freq): self.gpio_pwm.ChangeFrequency(freq) return True def duty_cycle(self, duty_cycle): self.gpio_pwm.ChangeDutyCycle(duty_cycle) return True def stop(self): """Spops all animation""" if self.fading: self.fader.stop() self.fading = False if self.pulsing: self.pulsing = False self.pulser.pause() if self.blinking: self.blinking = False #self.gpio_pwm.stop() #time.sleep(0.01) if self._value: self.duty_cycle(100) else: self.duty_cycle(0) #GPIO.output(self.pin, self._value) return True def stop_pulse(self): """Stops the pulsing thread @param self Object pointer.""" self.pulsing = False self.pulser.stop() self.pulser = Pulse(self, 0, 0, 0, 0) def brightness(self, value): if not 0 <= value <= 100: raise ValueError("Brightness must be between 0 and 100") self.frequency(PULSE_FREQUENCY) self.duty_cycle(value) def write(self, value): if value is not True and value is not False and value is not 1 and value is not 0: raise ValueError("You must write a value of 1/True or 0/False") self.stop() self._value = value self.frequency(PULSE_FREQUENCY) #print("Writing {} to pin {}".format(value, self.pin)) # GPIO.output(self.pin, value) if self._value: self.duty_cycle(100) else: self.duty_cycle(0) return True def on(self): """Turns an Output on @param self Object pointer.""" self.write(1) return True def off(self): """Turns an Output off @param self Object pointer.""" self.write(0) return True high = on low = off def toggle(self): self.stop() if self.read(): self.write(0) else: self.write(1) return True
class Output(Pin): type = 'Output' def __init__(self, pin): GPIO.setup(pin, GPIO.OUT, initial=0) super(Output,self).__init__(pin) self.gpio_pwm = GPIO.PWM(pin,1) self.pulser = Pulse(self,0,0,0,0) self.blinking = False self.pulsing = False self.fader = None ## Fades an LED to a specific brightness over a specific time def fade(self,start,end,duration): self.stop() time_start = time.time() self.pwm(PULSE_FREQUENCY,start) def _fade(): if time.time() - time_start >= duration: self.duty_cycle(end) return False current = (time.time() - time_start) / duration brightness = start + (float(end-start) * current) self.duty_cycle(round(brightness)) time.sleep(0.1) self.fader = AsyncWorker(_fade) self.fader.start() return True ## Blinks an LED by working out the correct PWM frequency/duty cycle # @param self Object pointer. # @param on Time the LED should stay at 100%/on # @param off Time the LED should stay at 0%/off def blink(self,on=1,off=-1): if off == -1: off = on off = float(off) on = float(on) total = off + on duty_cycle = 100.0 * (on/total) # Stop the thread that's pulsing the LED if self.pulsing: self.stop_pulse(); # Use pure PWM blinking, because threads are fugly if self.blinking: self.frequency(1.0/total) self.duty_cycle(duty_cycle) else: self.pwm(1.0/total,duty_cycle) self.blinking = True return True ## Pulses an LED # @param self Object pointer. # @param transition_on Time the transition from 0% to 100% brightness should take # @param transition_off Time the trantition from 100% to 0% brightness should take # @param time_on Time the LED should stay at 100% brightness # @param time_off Time the LED should stay at 0% brightness def pulse(self,transition_on=None,transition_off=None,time_on=None,time_off=None): # This needs a thread to handle the fade in and out # Attempt to cascade parameters # pulse() = pulse(0.5,0.5,0.5,0.5) # pulse(0.5,1.0) = pulse(0.5,1.0,0.5,0.5) # pulse(0.5,1.0,1.0) = pulse(0.5,1.0,1.0,1.0) # pulse(0.5,1.0,1.0,0.5) = - if transition_on == None: transition_on = 0.5 if transition_off == None: transition_off = transition_on if time_on == None: time_on = transition_on if time_off == None: time_off = transition_on # Fire up PWM if it's not running if self.blinking == False: self.pwm(PULSE_FREQUENCY,0.0) # pulse(x,y,0,0) is basically just a regular blink # only fire up a thread if we really need it if transition_on == 0 and transition_off == 0: self.blink(time_on,time_off) else: self.pulser.time_on = time_on self.pulser.time_off = time_off self.pulser.transition_on = transition_on self.pulser.transition_off = transition_off self.pulser.start() # Kick off the pulse thread self.pulsing = True self.blinking = True return True def pwm(self,freq,duty_cycle = 50): self.gpio_pwm.ChangeDutyCycle(duty_cycle) self.gpio_pwm.ChangeFrequency(freq) self.gpio_pwm.start(duty_cycle) return True def frequency(self,freq): self.gpio_pwm.ChangeFrequency(freq) return True def duty_cycle(self,duty_cycle): self.gpio_pwm.ChangeDutyCycle(duty_cycle) return True ## Stops the pulsing thread def stop(self): if self.fader != None: self.fader.stop() self.blinking = False self.stop_pulse() # Abruptly stopping PWM is a bad idea # unless we're writing a 1 or 0 # So don't inherit the parent classes # stop() since weird bugs happen # Threaded PWM access was aborting with # no errors when stop coincided with a # duty cycle change. return True ## Stops the pulsing thread # @param self Object pointer. def stop_pulse(self): self.pulsing = False self.pulser.stop() self.pulser = Pulse(self,0,0,0,0) def write(self,value): blinking = self.blinking self.stop() self.duty_cycle(100) self.gpio_pwm.stop() # Some gymnastics here to fix a bug ( in RPi.GPIO?) # That occurs when trying to output(1) immediately # after stopping the PWM # A small delay is needed. Ugly, but it works if blinking and value == 1: time.sleep(0.02) GPIO.output(self.pin,value) return True ## Turns an Output on # @param self Object pointer. # # Includes handling of pulsing/blinking functions # which must be stopped before turning on def on(self): self.write(1) return True ## Turns an Output off # @param self Object pointer. # # Includes handling of pulsing/blinking functions # which must be stopped before turning off def off(self): self.write(0) return True # Alias on/off to conventional names high = on low = off def toggle(self): if( self.blinking ): self.write(0) return True if( self.read() == 1 ): self.write(0) else: self.write(1) return True
def async_start(name, function): global workers workers[name] = AsyncWorker(function) workers[name].start() return True
class Output(Pin): """ExplorerHAT class representing a GPIO Output Output contains methods that apply only to outputs. It also contains methods for pulsing, blinking LEDs or other attached devices""" type = 'Output' def __init__(self, pin): GPIO.setup(pin, GPIO.OUT, initial=0) super(Output, self).__init__(pin) self.gpio_pwm = GPIO.PWM(pin, PULSE_FREQUENCY) self.gpio_pwm.start(0) self.pulser = Pulse(self, 0, 0, 0, 0) self.blinking = False self.pulsing = False self.fading = False self.fader = None self._value = 0 def __del__(self): self.gpio_pwm.stop() Pin.__del__(self) def fade(self, start, end, duration): """Fades an LED to a specific brightness over a specific time in seconds @param self Object pointer. @param start Starting brightness % @param end Ending brightness % @param duration Time duration ( in seconds ) of the fade""" self.stop() time_start = time.time() self.pwm(PULSE_FREQUENCY, start) def _fade(): self.fading = True if time.time() - time_start >= duration: self.duty_cycle(end) self.fading = False return False current = (time.time() - time_start) / duration brightness = start + (float(end-start) * current) self.duty_cycle(round(brightness)) time.sleep(1.0 / PULSE_FPS) self.fader = AsyncWorker(_fade) self.fader.start() return True def blink(self, on=1, off=-1): """Blinks an LED by working out the correct PWM frequency/duty cycle @param self Object pointer. @param on Time the LED should stay at 100%/on @param off Time the LED should stay at 0%/off""" self.stop() if off == -1: off = on off = float(off) on = float(on) total = off + on duty_cycle = 100.0 * (on/total) # Use pure PWM blinking, because threads are ugly self.frequency(1.0/total) self.duty_cycle(duty_cycle) self.blinking = True return True def pulse(self, transition_on=None, transition_off=None, time_on=None, time_off=None): """Pulses an LED @param self Object pointer. @param transition_on Time the transition from 0% to 100% brightness should take @param transition_off Time the trantition from 100% to 0% brightness should take @param time_on Time the LED should stay at 100% brightness @param time_off Time the LED should stay at 0% brightness""" self.stop() # This needs a thread to handle the fade in and out # Attempt to cascade parameters # pulse() = pulse(0.5,0.5,0.5,0.5) # pulse(0.5,1.0) = pulse(0.5,1.0,0.5,0.5) # pulse(0.5,1.0,1.0) = pulse(0.5,1.0,1.0,1.0) # pulse(0.5,1.0,1.0,0.5) = - if transition_on is None: transition_on = 0.5 if transition_off is None: transition_off = transition_on if time_on is None: time_on = transition_on if time_off is None: time_off = transition_on # pulse(x,y,0,0) is basically just a regular blink # only fire up a thread if we really need it if transition_on == 0 and transition_off == 0: self.blink(time_on, time_off) self.blinking = True else: self.pulser.time_on = time_on self.pulser.time_off = time_off self.pulser.transition_on = transition_on self.pulser.transition_off = transition_off self.pulser.start() self.pulsing = True return True def pwm(self, freq, duty_cycle=50): self.gpio_pwm.ChangeDutyCycle(duty_cycle) self.gpio_pwm.ChangeFrequency(freq) #self.gpio_pwm.start(duty_cycle) return True def frequency(self, freq): self.gpio_pwm.ChangeFrequency(freq) return True def duty_cycle(self, duty_cycle): self.gpio_pwm.ChangeDutyCycle(duty_cycle) return True def stop(self): """Spops all animation""" if self.fading: self.fader.stop() self.fading = False if self.pulsing: self.pulsing = False self.pulser.pause() if self.blinking: self.blinking = False #self.gpio_pwm.stop() #time.sleep(0.01) if self._value: self.duty_cycle(100) else: self.duty_cycle(0) #GPIO.output(self.pin, self._value) return True def stop_pulse(self): """Stops the pulsing thread @param self Object pointer.""" self.pulsing = False self.pulser.stop() self.pulser = Pulse(self, 0, 0, 0, 0) def brightness(self, value): if not 0 <= value <= 100: raise ValueError("Brightness must be between 0 and 100") self.frequency(PULSE_FREQUENCY) self.duty_cycle(value) def write(self, value): if value is not True and value is not False and value is not 1 and value is not 0: raise ValueError("You must write a value of 1/True or 0/False") self.stop() self._value = value self.frequency(PULSE_FREQUENCY) #print("Writing {} to pin {}".format(value, self.pin)) # GPIO.output(self.pin, value) if self._value: self.duty_cycle(100) else: self.duty_cycle(0) return True def on(self): """Turns an Output on @param self Object pointer.""" self.write(1) return True def off(self): """Turns an Output off @param self Object pointer.""" self.write(0) return True high = on low = off def toggle(self): self.stop() if self.read(): self.write(0) else: self.write(1) return True