Ejemplo n.º 1
0
def sector_pulse_1d(t, dt, x, y, prev_state, in_color):
    part = rpi_ws281x.perlin_noise_3d(0, 0, t)
    v = 1 - utils.clamp(abs(x - part) * 10, 0, 1)
    return in_color, v


def sector_pulse_2_1d(t, dt, x, y, prev_state, in_color):
    part = rpi_ws281x.perlin_noise_3d(x, 0, t)
    v = 1 - utils.clamp(abs(x - part) * 10, 0, 1)
    return in_color, v


default_secondary = {
    0: None,
    1: sine_1d,
    2: cubic_1d,
    3: ramp_1d,
    4: bounce_linear_1d,
    5: bounce_sine_1d,
    6: bounce_cubic_1d,
    6: perlin_noise_2d,
    7: twinkle_pulse_1d,
    8: sector_pulse_1d,
    9: sector_pulse_2_1d,
}

default_secondary_names = {
    k: utils.snake_to_title(v.__name__) if v else 'None'
    for k, v in default_secondary.items()
}
Ejemplo n.º 2
0
def create_app(led_count, refresh_rate, led_pin, led_data_rate,
               led_dma_channel, led_pixel_order, led_color_correction,
               led_v_limit, save_interval, allow_direct_control):
    app = Flask(__name__)
    leds = LEDController(led_count, led_pin, led_data_rate, led_dma_channel,
                         led_pixel_order)
    controller = AnimationController(leds, refresh_rate, led_count,
                                     pixelmappings.line(led_count),
                                     led_color_correction)

    patterns = dict(animpatterns.default)

    # Create file if it doesn't exist already
    filename = Path('/etc') / 'ledcontrol.json'
    filename.touch(exist_ok=True)

    # Init controller params and custom patterns from settings file
    with open(str(filename), mode='r') as data_file:
        try:
            settings = json.loads(data_file.read().replace('master_', ''))
            # Enforce brightness limit
            settings['params']['brightness'] = min(
                settings['params']['brightness'], led_v_limit)
            # Set controller params, recalculate things that depend on params
            controller.params.update(settings['params'])
            controller.params['direct_control_mode'] = 0
            controller.calculate_color_correction()
            controller.calculate_mappings()
            # Read custom patterns and changed params for default patterns
            for k, v in settings['patterns'].items():
                # JSON keys are always strings
                if int(k) not in animpatterns.default:
                    patterns[int(k)] = v
                    controller.set_pattern_function(int(k), v['source'])
                else:
                    patterns[int(k)].update(v)
            # Read color palettes
            controller.palettes.update(
                {int(k): v
                 for k, v in settings['palettes'].items()})
            controller.calculate_palette_table()
            print(f'Loaded saved settings from {filename}.')
        except Exception:
            print(f'Could not open saved settings at {filename}, ignoring.')

    # Define form and create user-facing labels based on keys
    form = [
        FormItem('range', 'brightness', float, 0, led_v_limit, 0.05),
        FormItem('range', 'color_temp', int, 1000, 12000, 10, unit='K'),
        #FormItem('range', 'gamma', float, 0.01, 3),
        FormItem('range', 'saturation', float, 0, 1),
        FormItem('select', 'primary_pattern', int),
        FormItem('range', 'primary_speed', float, 0, 2, unit='Hz'),
        FormItem('range', 'primary_scale', float, -10, 10),
        FormItem('code'),
        FormItem('select',
                 'secondary_pattern',
                 int,
                 options=list(animpatterns.default_secondary_names.values()),
                 val=controller.params['secondary_pattern']),
        FormItem('range', 'secondary_speed', float, 0.01, 2, unit='Hz'),
        FormItem('range', 'secondary_scale', float, -10, 10),
        FormItem('select', 'palette', int),
        FormItem('colors'),
    ]

    if allow_direct_control:
        form.append(
            FormItem('select',
                     'direct_control_mode',
                     int,
                     options=['Off', 'On']))

    for item in form:
        item.label = utils.snake_to_title(item.key)

    @app.route('/')
    def index():
        'Returns web app page'
        for item in form:
            if (item.key in controller.params):
                item.val = item.type(controller.params[item.key])
        return render_template('index.html', form=form)

    @app.route('/setparam')
    def set_param():
        'Sets a key/value pair in controller parameters'
        key = request.args.get('key', type=str)
        value = request.args.get('value')
        if key == 'primary_pattern':
            save_current_pattern_params()
            controller.set_param('primary_speed',
                                 patterns[int(value)]['primary_speed'])
            controller.set_param('primary_scale',
                                 patterns[int(value)]['primary_scale'])
        controller.set_param(
            key,
            next(filter(lambda i: i.key == key, form)).type(value))
        return jsonify(result='')

    @app.route('/getpatternparams')
    def get_pattern_params():
        'Returns pattern parameters for the given pattern in JSON dict form'
        key = request.args.get('key', type=int)
        return jsonify(speed=patterns[key]['primary_speed'],
                       scale=patterns[key]['primary_scale'])

    @app.route('/getpatternsources')
    def get_pattern_sources():
        'Returns pattern sources in JSON dict form'
        return jsonify(sources={k: v['source']
                                for k, v in patterns.items()},
                       names={k: v['name']
                              for k, v in patterns.items()},
                       defaults=list(animpatterns.default.keys()),
                       current=controller.params['primary_pattern'])

    @app.route('/compilepattern')
    def compile_pattern():
        'Compiles a pattern, returns errors and warnings in JSON array form'
        key = request.args.get('key', type=int)
        source = request.args.get('source', type=str)
        if key not in patterns:
            patterns[key] = {
                'name': key,
                'primary_speed': controller.params['primary_speed'],
                'primary_scale': controller.params['primary_scale']
            }
        patterns[key]['source'] = source
        errors, warnings = controller.set_pattern_function(key, source)
        return jsonify(errors=errors, warnings=warnings)

    @app.route('/setpatternname')
    def set_pattern_name():
        'Sets a pattern name for the given key'
        key = request.args.get('key', type=int)
        name = request.args.get('name', type=str)
        patterns[key]['name'] = name
        return jsonify(result='')

    @app.route('/deletepattern')
    def delete_pattern():
        'Deletes a pattern'
        key = request.args.get('key', type=int)
        del patterns[key]
        return jsonify(result='')

    @app.route('/getpalettes')
    def get_palettes():
        'Returns palettes in JSON dict form'
        return jsonify(palettes=controller.palettes,
                       defaults=list(colorpalettes.default.keys()),
                       current=controller.params['palette'])

    @app.route('/setpalette')
    def set_palette():
        'Sets a palette'
        key = request.args.get('key', type=int)
        value = json.loads(request.args.get('value', type=str))
        controller.set_palette(key, value)
        controller.calculate_palette_table()
        return jsonify(result='')

    @app.route('/deletepalette')
    def delete_palette():
        'Deletes a palette'
        key = request.args.get('key', type=int)
        controller.delete_palette(key)
        return jsonify(result='')

    @app.route('/getfps')
    def get_fps():
        'Returns latest animation frames per second'
        return jsonify(fps=controller.timer.get_rate())

    def save_current_pattern_params():
        'Remembers speed and scale for current pattern'
        patterns[controller.params['primary_pattern']]['primary_speed']\
            = controller.params['primary_speed']
        patterns[controller.params['primary_pattern']]['primary_scale']\
            = controller.params['primary_scale']

    def save_settings():
        'Save controller settings'
        save_current_pattern_params()
        patterns_save, palettes_save = {}, {}
        for k, v in patterns.items():
            if k not in animpatterns.default:
                patterns_save[k] = v
            else:
                patterns_save[k] = {
                    n: v[n]
                    for n in ('primary_speed', 'primary_scale')
                }
        for k, v in controller.palettes.items():
            if k not in colorpalettes.default:
                palettes_save[k] = v
        data = {
            'params': controller.params,
            'patterns': patterns_save,
            'palettes': palettes_save,
        }
        with open(str(filename), 'w') as data_file:
            try:
                json.dump(data, data_file, sort_keys=True, indent=4)
                print(f'Saved settings to {filename}.')
            except Exception:
                print(f'Could not save settings to {filename}.')

    def auto_save_settings():
        'Timer for automatically saving settings'
        save_settings()
        t = Timer(save_interval, auto_save_settings)
        t.daemon = True
        t.start()

    controller.begin_animation_thread()
    atexit.register(save_settings)
    atexit.register(controller.clear_leds)
    atexit.register(controller.end_animation)
    auto_save_settings()

    return app
Ejemplo n.º 3
0
def create_app(led_count, refresh_rate, led_pin, led_data_rate,
               led_dma_channel, led_strip_type, led_pixel_order,
               led_color_correction, led_brightness_limit, save_interval):
    app = Flask(__name__)
    leds = LEDController(led_count, led_pin, led_data_rate, led_dma_channel,
                         led_strip_type, led_pixel_order)
    controller = AnimationController(leds, refresh_rate, led_count,
                                     pixelmappings.line(led_count),
                                     led_color_correction)

    pattern_names = dict(patterns.default_names)

    # Create file if it doesn't exist already
    filename = Path.cwd() / 'ledcontrol.json'
    filename.touch(exist_ok=True)

    # Init controller params and custom patterns from settings file
    with open(str(filename), mode='r') as data_file:
        try:
            settings = json.load(data_file)
            controller.params = settings['params']
            # Enforce brightness limit
            controller.params['master_brightness'] = min(
                controller.params['master_brightness'], led_brightness_limit)
            controller.calculate_color_correction()
            controller.calculate_mappings()
            for k, v in settings['pattern_sources'].items():
                # JSON keys are always strings
                controller.set_pattern_function(int(k), v)
            for k, v in settings['pattern_names'].items():
                pattern_names[int(k)] = v
            controller.colors = settings['colors']
            print(f'Loaded saved settings from {filename}.')
        except Exception:
            print(f'Could not open saved settings at {filename}, ignoring.')

    # Define form and create user-facing labels based on keys
    form = [
        FormItem('range', 'master_brightness', float, 0, led_brightness_limit,
                 0.05),
        FormItem('range', 'master_color_temp', int, 1000, 12000, 10, unit='K'),
        FormItem('range', 'master_gamma', float, 0.01, 3),
        FormItem('range', 'master_saturation', float, 0, 1),
        FormItem('select', 'primary_pattern', int),
        FormItem('range', 'primary_speed', float, 0.01, 2, unit='Hz'),
        FormItem('range', 'primary_scale', float, -10, 10),
        FormItem('code', 'pattern_source', str),
        FormItem('select',
                 'secondary_pattern',
                 int,
                 options=list(patterns.default_secondary_names.values()),
                 val=controller.params['secondary_pattern']),
        FormItem('range', 'secondary_speed', float, 0.01, 2, unit='Hz'),
        FormItem('range', 'secondary_scale', float, -10, 10),
    ]

    for item in form:
        item.label = utils.snake_to_title(item.key)

    @app.route('/')
    def index():
        'Returns web app page'
        for item in form:
            if (item.key in controller.params):
                item.val = item.type(controller.params[item.key])
        return render_template('index.html',
                               form=form,
                               params=controller.params,
                               colors=controller.colors)

    @app.route('/setparam')
    def set_param():
        'Sets a key/value pair in controller parameters'
        key = request.args.get('key', type=str)
        value = request.args.get('value')
        controller.set_param(
            key,
            next(filter(lambda i: i.key == key, form)).type(value))
        return jsonify(result='')

    @app.route('/getpatternsources')
    def get_pattern_sources():
        'Returns pattern sources in JSON dict form'
        return jsonify(sources=controller.pattern_sources,
                       names=pattern_names,
                       defaults=list(patterns.default.keys()),
                       current=controller.params['primary_pattern'])

    @app.route('/compilepattern')
    def compile_pattern():
        'Compiles a pattern, returns errors and warnings in JSON array form'
        key = request.args.get('key', type=int)
        source = request.args.get('source', type=str)
        errors, warnings = controller.set_pattern_function(key, source)
        return jsonify(errors=errors, warnings=warnings)

    @app.route('/setpatternname')
    def set_pattern_name():
        'Sets a pattern name for the given key'
        key = request.args.get('key', type=int)
        name = request.args.get('name', type=str)
        pattern_names[key] = name
        return jsonify(result='')

    @app.route('/setcolor')
    def set_color():
        'Sets a color in the palette'
        index = request.args.get('index', type=int)
        h = round(request.args.get('h', type=float), 3)
        s = round(request.args.get('s', type=float), 3)
        v = round(request.args.get('v', type=float), 3)
        controller.set_color(index, (h, s, v))
        return jsonify(result='')

    @app.route('/setcolorcomponent')
    def set_color_component():
        'Sets a component of a color in the palette'
        index = request.args.get('index', type=int)
        component = request.args.get('component', type=int)
        value = request.args.get('value', type=float)
        controller.set_color_component(index, component, value)
        return jsonify(result='')

    def save_settings():
        'Save controller settings'
        data = {
            'params': controller.params,
            'pattern_sources': {
                k: v
                for k, v in controller.pattern_sources.items()
                if k not in patterns.default
            },
            'pattern_names': {
                k: v
                for k, v in pattern_names.items()
                if k not in patterns.default_names
            },
            'colors': controller.colors,
        }
        with open(str(filename), 'w') as data_file:
            try:
                json.dump(data,
                          data_file,
                          sort_keys=True,
                          indent=4,
                          separators=(',', ': '))
                print(f'Saved settings to {filename}.')
            except Exception:
                print(f'Could not save settings to {filename}.')

    def auto_save_settings():
        'Timer for automatically saving settings'
        save_settings()
        t = Timer(save_interval, auto_save_settings)
        t.daemon = True
        t.start()

    controller.begin_animation_thread()
    atexit.register(save_settings)
    atexit.register(leds.clear)
    atexit.register(controller.end_animation_thread)
    auto_save_settings()

    return app