示例#1
0
    def set_light(self, pin, use_overrides=False, brightness=1.0):
        """Set the brightness of the specified light

        Taking into account various overrides if specified.
        The default is full on (1.0)
        To turn a light off pass 0 for brightness
        If brightness is a float between 0 and 1.0 that level
        will be set.

        This function replaces turn_on_light and turn_off_light

        :param pin: index of pin in CM.hardware.gpio_pins
        :type pin: int

        :param use_overrides: should overrides be used
        :type use_overrides: bool

        :param brightness: float, a float representing the brightness of the lights
        :type brightness: float
        """
        if math.isnan(brightness):
            brightness = 0.0

        if hc._ACTIVE_LOW_MODE:
            brightness = 1.0 - brightness

        if use_overrides:
            if pin + 1 in hc.always_off_channels:
                brightness = 0
            elif pin + 1 in hc.always_on_channels:
                brightness = 1

            if pin + 1 in hc.inverted_channels:
                brightness = 1 - brightness

        if hc.is_pin_pwm(pin):
            brightness = int(brightness * self.pwm_max)
            if self.gpioactive:
                brightness = 100 - brightness
            level = '#{0:02X}{1:02X}{2:02X}'.format(
                255, int(ceil(brightness * 2.55)),
                int(ceil(brightness * 2.55)))
            try:
                item = self.gpio[pin]
                print item, level, brightness, int(ceil(brightness * 2.55))
                self.itemconfig(item, fill=level)
                self.parent.update()
            except:
                pass
        else:
            item = self.gpio[pin]
            onoff = int(brightness > .5)
            if self.gpioactive:
                onoff = 1 - onoff
            color = (self.blue, self.white)[onoff]
            try:
                self.itemconfig(item, fill=color)
                self.parent.update()
            except:
                pass
def update_lights(matrix, mean, std):
    """
    Update the state of all the lights

    Update the state of all the lights based upon the current
    frequency response matrix
    """
    for i in range(0, hc.GPIOLEN):
        # Calculate output pwm, where off is at some portion of the std below
        # the mean and full on is at some portion of the std above the mean.
        brightness = matrix[i] - mean[i] + 0.5 * std[i]
        brightness = brightness / (1.25 * std[i])
        if brightness > 1.0:
            brightness = 1.0
        if brightness < 0:
            brightness = 0
        if not hc.is_pin_pwm(i):
            # If pin is on / off mode we'll turn on at 1/2 brightness
            if (brightness > 0.5):
                hc.turn_on_light(i, True)
            else:
                hc.turn_off_light(i, True)
        else:
            hc.turn_on_light(i, True, brightness)
def main():
    '''main'''
    song_to_play = int(cm.get_state('song_to_play', 0))
    play_now = int(cm.get_state('play_now', 0))

    # Arguments
    parser = argparse.ArgumentParser()
    filegroup = parser.add_mutually_exclusive_group()
    filegroup.add_argument('--playlist', default=_PLAYLIST_PATH,
                           help='Playlist to choose song from.')
    filegroup.add_argument('--file', help='path to the song to play (required if no'
                           'playlist is designated)')
    parser.add_argument('--readcache', type=int, default=1,
                        help='read light timing from cache if available. Default: true')
    args = parser.parse_args()

    # Log everything to our log file
    # TODO(todd): Add logging configuration options.
    logging.basicConfig(filename=cm.LOG_DIR + '/music_and_lights.play.dbg',
                        format='[%(asctime)s] %(levelname)s {%(pathname)s:%(lineno)d}'
                        ' - %(message)s',
                        level=logging.DEBUG)

    # Make sure one of --playlist or --file was specified
    if args.file == None and args.playlist == None:
        print "One of --playlist or --file must be specified"
        sys.exit()

    # Initialize Lights
    hc.initialize()

    # Only execute preshow if no specific song has been requested to be played right now
    if not play_now:
        execute_preshow(cm.lightshow()['preshow'])

    # Determine the next file to play
    song_filename = args.file
    if args.playlist != None and args.file == None:
        most_votes = [None, None, []]
        current_song = None
        with open(args.playlist, 'rb') as playlist_fp:
            fcntl.lockf(playlist_fp, fcntl.LOCK_SH)
            playlist = csv.reader(playlist_fp, delimiter='\t')
            songs = []
            for song in playlist:
                if len(song) < 2 or len(song) > 4:
                    logging.error('Invalid playlist.  Each line should be in the form: '
                                 '<song name><tab><path to song>')
                    sys.exit()
                elif len(song) == 2:
                    song.append(set())
                else:
                    song[2] = set(song[2].split(','))
                    if len(song) == 3 and len(song[2]) >= len(most_votes[2]):
                        most_votes = song
                songs.append(song)
            fcntl.lockf(playlist_fp, fcntl.LOCK_UN)

        if most_votes[0] != None:
            logging.info("Most Votes: " + str(most_votes))
            current_song = most_votes

            # Update playlist with latest votes
            with open(args.playlist, 'wb') as playlist_fp:
                fcntl.lockf(playlist_fp, fcntl.LOCK_EX)
                writer = csv.writer(playlist_fp, delimiter='\t')
                for song in songs:
                    if current_song == song and len(song) == 3:
                        song.append("playing!")
                    if len(song[2]) > 0:
                        song[2] = ",".join(song[2])
                    else:
                        del song[2]
                writer.writerows(songs)
                fcntl.lockf(playlist_fp, fcntl.LOCK_UN)

        else:
            # Get random song
            if _RANDOMIZE_PLAYLIST:
                current_song = songs[random.randint(0, len(songs) - 1)]
            # Get a "play now" requested song
            elif play_now > 0 and play_now <= len(songs):
                current_song = songs[play_now - 1]
            # Play next song in the lineup
            else:
                song_to_play = song_to_play if (song_to_play <= len(songs) - 1) else 0
                current_song = songs[song_to_play]
                next_song = (song_to_play + 1) if ((song_to_play + 1) <= len(songs) - 1) else 0
                cm.update_state('song_to_play', next_song)

        # Get filename to play and store the current song playing in state cfg
        song_filename = current_song[1]
        cm.update_state('current_song', songs.index(current_song))

    song_filename = song_filename.replace("$SYNCHRONIZED_LIGHTS_HOME", cm.HOME_DIR)

    # Ensure play_now is reset before beginning playback
    if play_now:
        cm.update_state('play_now', 0)
        play_now = 0

    # Initialize FFT stats
    matrix = [0 for _ in range(hc.GPIOLEN)]
    offct = [0 for _ in range(hc.GPIOLEN)]

    # Build the limit list
    if len(_LIMIT_LIST) == 1:
        limit = [_LIMIT_LIST[0] for _ in range(hc.GPIOLEN)]
    else:
        limit = _LIMIT_LIST

    # Set up audio
    if song_filename.endswith('.wav'):
        musicfile = wave.open(song_filename, 'r')
    else:
        musicfile = decoder.open(song_filename)

    sample_rate = musicfile.getframerate()
    num_channels = musicfile.getnchannels()
    output = aa.PCM(aa.PCM_PLAYBACK, aa.PCM_NORMAL)
    output.setchannels(num_channels)
    output.setrate(sample_rate)
    output.setformat(aa.PCM_FORMAT_S16_LE)
    output.setperiodsize(CHUNK_SIZE)

    # Output a bit about what we're about to play
    song_filename = os.path.abspath(song_filename)
    logging.info("Playing: " + song_filename + " (" + str(musicfile.getnframes() / sample_rate)
                 + " sec)")

    cache = []
    cache_found = False
    cache_filename = os.path.dirname(song_filename) + "/." + os.path.basename(song_filename) \
        + ".sync.gz"
    # The values 12 and 1.5 are good estimates for first time playing back (i.e. before we have
    # the actual mean and standard deviations calculated for each channel).
    mean = [12.0 for _ in range(hc.GPIOLEN)]
    std = [1.5 for _ in range(hc.GPIOLEN)]
    if args.readcache:
        # Read in cached fft
        try:
            with gzip.open(cache_filename, 'rb') as playlist_fp:
                cachefile = csv.reader(playlist_fp, delimiter=',')
                for row in cachefile:
                    cache.append([0.0 if np.isinf(float(item)) else float(item) for item in row])
                cache_found = True
                # TODO(todd): Optimize this and / or cache it to avoid delay here
                cache_matrix = np.array(cache)
                for i in range(0, hc.GPIOLEN):
                    std[i] = np.std([item for item in cache_matrix[:, i] if item > 0])
                    mean[i] = np.mean([item for item in cache_matrix[:, i] if item > 0])
                logging.debug("std: " + str(std) + ", mean: " + str(mean))
        except IOError:
            logging.warn("Cached sync data song_filename not found: '" + cache_filename
                         + ".  One will be generated.")

    # Process audio song_filename
    row = 0
    data = musicfile.readframes(CHUNK_SIZE)
    frequency_limits = calculate_channel_frequency(_MIN_FREQUENCY,
                                                   _MAX_FREQUENCY,
                                                   _CUSTOM_CHANNEL_MAPPING,
                                                   _CUSTOM_CHANNEL_FREQUENCIES)

    while data != '' and not play_now:
        output.write(data)

        # Control lights with cached timing values if they exist
        matrix = None
        if cache_found and args.readcache:
            if row < len(cache):
                matrix = cache[row]
            else:
                logging.warning("Ran out of cached FFT values, will update the cache.")
                cache_found = False

        if matrix == None:
            # No cache - Compute FFT in this chunk, and cache results
            matrix = calculate_levels(data, sample_rate, frequency_limits)
            cache.append(matrix)


        # blank out the display
        led.fill(Color(0,0,0),0,151)
        for i in range(0, hc.GPIOLEN):
            if hc.is_pin_pwm(i):
                # Output pwm, where off is at 0.5 std below the mean
                # and full on is at 0.75 std above the mean.

                display_column(i,matrix[i])

                #brightness = matrix[i] - mean[i] + 0.5 * std[i]
                #brightness = brightness / (1.25 * std[i])
                #if brightness > 1.0:
                    #brightness = 1.0
                #if brightness < 0:
                    #brightness = 0
                #hc.turn_on_light(i, True, int(brightness * 60))
            else:
                if limit[i] < matrix[i] * _LIMIT_THRESHOLD:
                    limit[i] = limit[i] * _LIMIT_THRESHOLD_INCREASE
                    logging.debug("++++ channel: {0}; limit: {1:.3f}".format(i, limit[i]))
                # Amplitude has reached threshold
                if matrix[i] > limit[i]:
                    hc.turn_on_light(i, True)
                    offct[i] = 0
                else:  # Amplitude did not reach threshold
                    offct[i] = offct[i] + 1
                    if offct[i] > _MAX_OFF_CYCLES:
                        offct[i] = 0
                        limit[i] = limit[i] * _LIMIT_THRESHOLD_DECREASE  # old value 0.8
                    logging.debug("---- channel: {0}; limit: {1:.3f}".format(i, limit[i]))
                    hc.turn_off_light(i, True)

        # send out data to RGB LED Strip
        led.update()
        # Read next chunk of data from music song_filename
        data = musicfile.readframes(CHUNK_SIZE)
        row = row + 1

        # Load new application state in case we've been interrupted
        cm.load_state()
        play_now = int(cm.get_state('play_now', 0))

    if not cache_found:
        with gzip.open(cache_filename, 'wb') as playlist_fp:
            writer = csv.writer(playlist_fp, delimiter=',')
            writer.writerows(cache)
            logging.info("Cached sync data written to '." + cache_filename
                         + "' [" + str(len(cache)) + " rows]")

    # We're done, turn it all off ;)
    hc.clean_up()
示例#4
0
def main():
    """
    PWM example

    Start at each end and walk to the other using pwm
    """
    # this is a list of all the channels you have access to
    lights = hc._GPIO_PINS

    # the gpio pins in reversed order
    lights2 = lights[::-1]

    # get _PWM_MAX from the hc module
    # this is the max value for the pwm channels
    pwm_max = hc._PWM_MAX
    # initialize your hardware for use
    hc.initialize()

    # start with all the lights off
    hc.turn_off_lights()

    # pause for 1 second
    time.sleep(1)

    # working loop, we will do this sequence 10 times then end
    for _ in range(10):
        # here we just loop over the gpio pins and turn then on and off
        # with the pwm feature of lightshowpi
        for light in range(int(len(lights) / 2)):
            if hc.is_pin_pwm(lights[light]) and hc.is_pin_pwm(lights2[light]):
                for brightness in range(0, pwm_max):
                    # fade in
                    hc.turn_on_light(lights[light], 0,
                                     float(brightness) / pwm_max)

                    hc.turn_on_light(lights2[light], 0,
                                     float(brightness) / pwm_max)

                    time.sleep(.05 / pwm_max)

                for brightness in range(pwm_max - 1, -1, -1):
                    # fade out
                    hc.turn_on_light(lights[light], 0,
                                     float(brightness) / pwm_max)

                    hc.turn_on_light(lights2[light], 0,
                                     float(brightness) / pwm_max)

                    time.sleep(.05 / pwm_max)

        for light in range(int(len(lights) / 2) - 1, -1, -1):
            if hc.is_pin_pwm(lights[light]) and hc.is_pin_pwm(lights2[light]):
                for brightness in range(0, pwm_max):
                    # fade in
                    hc.turn_on_light(lights[light], 0,
                                     float(brightness) / pwm_max)

                    hc.turn_on_light(lights2[light], 0,
                                     float(brightness) / pwm_max)

                    time.sleep(.05 / pwm_max)

                for brightness in range(pwm_max - 1, -1, -1):
                    # fade out
                    hc.turn_on_light(lights[light], 0,
                                     float(brightness) / pwm_max)

                    hc.turn_on_light(lights2[light], 0,
                                     float(brightness) / pwm_max)

                    time.sleep(.05 / pwm_max)

    # This ends and cleans up everything
    hc.clean_up()
def main():
    '''main'''
    song_to_play = int(cm.get_state('song_to_play', 0))
    play_now = int(cm.get_state('play_now', 0))

    # Arguments
    parser = argparse.ArgumentParser()
    filegroup = parser.add_mutually_exclusive_group()
    filegroup.add_argument('--playlist',
                           default=_PLAYLIST_PATH,
                           help='Playlist to choose song from.')
    filegroup.add_argument('--file',
                           help='path to the song to play (required if no'
                           'playlist is designated)')
    parser.add_argument(
        '--readcache',
        type=int,
        default=1,
        help='read light timing from cache if available. Default: true')
    args = parser.parse_args()

    # Log everything to our log file
    # TODO(todd): Add logging configuration options.
    logging.basicConfig(
        filename=cm.LOG_DIR + '/music_and_lights.play.dbg',
        format='[%(asctime)s] %(levelname)s {%(pathname)s:%(lineno)d}'
        ' - %(message)s',
        level=logging.DEBUG)

    # Make sure one of --playlist or --file was specified
    if args.file == None and args.playlist == None:
        print "One of --playlist or --file must be specified"
        sys.exit()

    # Initialize Lights
    hc.initialize()

    # Only execute preshow if no specific song has been requested to be played right now
    if not play_now:
        execute_preshow(cm.lightshow()['preshow'])

    # Determine the next file to play
    song_filename = args.file
    if args.playlist != None and args.file == None:
        most_votes = [None, None, []]
        current_song = None
        with open(args.playlist, 'rb') as playlist_fp:
            fcntl.lockf(playlist_fp, fcntl.LOCK_SH)
            playlist = csv.reader(playlist_fp, delimiter='\t')
            songs = []
            for song in playlist:
                if len(song) < 2 or len(song) > 4:
                    logging.error(
                        'Invalid playlist.  Each line should be in the form: '
                        '<song name><tab><path to song>')
                    sys.exit()
                elif len(song) == 2:
                    song.append(set())
                else:
                    song[2] = set(song[2].split(','))
                    if len(song) == 3 and len(song[2]) >= len(most_votes[2]):
                        most_votes = song
                songs.append(song)
            fcntl.lockf(playlist_fp, fcntl.LOCK_UN)

        if most_votes[0] != None:
            logging.info("Most Votes: " + str(most_votes))
            current_song = most_votes

            # Update playlist with latest votes
            with open(args.playlist, 'wb') as playlist_fp:
                fcntl.lockf(playlist_fp, fcntl.LOCK_EX)
                writer = csv.writer(playlist_fp, delimiter='\t')
                for song in songs:
                    if current_song == song and len(song) == 3:
                        song.append("playing!")
                    if len(song[2]) > 0:
                        song[2] = ",".join(song[2])
                    else:
                        del song[2]
                writer.writerows(songs)
                fcntl.lockf(playlist_fp, fcntl.LOCK_UN)

        else:
            # Get random song
            if _RANDOMIZE_PLAYLIST:
                current_song = songs[random.randint(0, len(songs) - 1)]
            # Get a "play now" requested song
            elif play_now > 0 and play_now <= len(songs):
                current_song = songs[play_now - 1]
            # Play next song in the lineup
            else:
                song_to_play = song_to_play if (
                    song_to_play <= len(songs) - 1) else 0
                current_song = songs[song_to_play]
                next_song = (song_to_play + 1) if (
                    (song_to_play + 1) <= len(songs) - 1) else 0
                cm.update_state('song_to_play', next_song)

        # Get filename to play and store the current song playing in state cfg
        song_filename = current_song[1]
        cm.update_state('current_song', songs.index(current_song))

    song_filename = song_filename.replace("$SYNCHRONIZED_LIGHTS_HOME",
                                          cm.HOME_DIR)

    # Ensure play_now is reset before beginning playback
    if play_now:
        cm.update_state('play_now', 0)
        play_now = 0

    # Initialize FFT stats
    matrix = [0 for _ in range(hc.GPIOLEN)]
    offct = [0 for _ in range(hc.GPIOLEN)]

    # Build the limit list
    if len(_LIMIT_LIST) == 1:
        limit = [_LIMIT_LIST[0] for _ in range(hc.GPIOLEN)]
    else:
        limit = _LIMIT_LIST

    # Set up audio
    if song_filename.endswith('.wav'):
        musicfile = wave.open(song_filename, 'r')
    else:
        musicfile = decoder.open(song_filename)

    sample_rate = musicfile.getframerate()
    num_channels = musicfile.getnchannels()
    output = aa.PCM(aa.PCM_PLAYBACK, aa.PCM_NORMAL)
    output.setchannels(num_channels)
    output.setrate(sample_rate)
    output.setformat(aa.PCM_FORMAT_S16_LE)
    output.setperiodsize(CHUNK_SIZE)

    # Output a bit about what we're about to play
    song_filename = os.path.abspath(song_filename)
    logging.info("Playing: " + song_filename + " (" +
                 str(musicfile.getnframes() / sample_rate) + " sec)")

    cache = []
    cache_found = False
    cache_filename = os.path.dirname(song_filename) + "/." + os.path.basename(song_filename) \
        + ".sync.gz"
    # The values 12 and 1.5 are good estimates for first time playing back (i.e. before we have
    # the actual mean and standard deviations calculated for each channel).
    mean = [12.0 for _ in range(hc.GPIOLEN)]
    std = [1.5 for _ in range(hc.GPIOLEN)]
    if args.readcache:
        # Read in cached fft
        try:
            with gzip.open(cache_filename, 'rb') as playlist_fp:
                cachefile = csv.reader(playlist_fp, delimiter=',')
                for row in cachefile:
                    cache.append([
                        0.0 if np.isinf(float(item)) else float(item)
                        for item in row
                    ])
                cache_found = True
                # TODO(todd): Optimize this and / or cache it to avoid delay here
                cache_matrix = np.array(cache)
                for i in range(0, hc.GPIOLEN):
                    std[i] = np.std(
                        [item for item in cache_matrix[:, i] if item > 0])
                    mean[i] = np.mean(
                        [item for item in cache_matrix[:, i] if item > 0])
                logging.debug("std: " + str(std) + ", mean: " + str(mean))
        except IOError:
            logging.warn("Cached sync data song_filename not found: '" +
                         cache_filename + ".  One will be generated.")

    # Process audio song_filename
    row = 0
    data = musicfile.readframes(CHUNK_SIZE)
    frequency_limits = calculate_channel_frequency(
        _MIN_FREQUENCY, _MAX_FREQUENCY, _CUSTOM_CHANNEL_MAPPING,
        _CUSTOM_CHANNEL_FREQUENCIES)

    while data != '' and not play_now:
        output.write(data)

        # Control lights with cached timing values if they exist
        matrix = None
        if cache_found and args.readcache:
            if row < len(cache):
                matrix = cache[row]
            else:
                logging.warning(
                    "Ran out of cached FFT values, will update the cache.")
                cache_found = False

        if matrix == None:
            # No cache - Compute FFT in this chunk, and cache results
            matrix = calculate_levels(data, sample_rate, frequency_limits)
            cache.append(matrix)

        # blank out the display
        led.fill(Color(0, 0, 0), 0, 151)
        for i in range(0, hc.GPIOLEN):
            if hc.is_pin_pwm(i):
                # Output pwm, where off is at 0.5 std below the mean
                # and full on is at 0.75 std above the mean.

                display_column(i, matrix[i])

                #brightness = matrix[i] - mean[i] + 0.5 * std[i]
                #brightness = brightness / (1.25 * std[i])
                #if brightness > 1.0:
                #brightness = 1.0
                #if brightness < 0:
                #brightness = 0
                #hc.turn_on_light(i, True, int(brightness * 60))
            else:
                if limit[i] < matrix[i] * _LIMIT_THRESHOLD:
                    limit[i] = limit[i] * _LIMIT_THRESHOLD_INCREASE
                    logging.debug("++++ channel: {0}; limit: {1:.3f}".format(
                        i, limit[i]))
                # Amplitude has reached threshold
                if matrix[i] > limit[i]:
                    hc.turn_on_light(i, True)
                    offct[i] = 0
                else:  # Amplitude did not reach threshold
                    offct[i] = offct[i] + 1
                    if offct[i] > _MAX_OFF_CYCLES:
                        offct[i] = 0
                        limit[i] = limit[
                            i] * _LIMIT_THRESHOLD_DECREASE  # old value 0.8
                    logging.debug("---- channel: {0}; limit: {1:.3f}".format(
                        i, limit[i]))
                    hc.turn_off_light(i, True)

        # send out data to RGB LED Strip
        led.update()
        # Read next chunk of data from music song_filename
        data = musicfile.readframes(CHUNK_SIZE)
        row = row + 1

        # Load new application state in case we've been interrupted
        cm.load_state()
        play_now = int(cm.get_state('play_now', 0))

    if not cache_found:
        with gzip.open(cache_filename, 'wb') as playlist_fp:
            writer = csv.writer(playlist_fp, delimiter=',')
            writer.writerows(cache)
            logging.info("Cached sync data written to '." + cache_filename +
                         "' [" + str(len(cache)) + " rows]")

    # We're done, turn it all off ;)
    hc.clean_up()