Pico Link — A YAML-Based Controller for Lutron Pico Remotes

Pico Link — A YAML-Based Controller for Lutron Pico Remotes

This project provides a flexible way to use Lutron Caseta Pico remotes (including the newer Paddle Pico) as general-purpose controllers inside Home Assistant. The integration listens to lutron_caseta_button_event and translates presses, holds, and releases into more predictable, domain-aware actions.


What the Integration Does

The goal of Pico Link is to take the raw button events exposed by the Lutron Caseta integration and provide a structured, deterministic control model. It handles the timing, ramping, and action decisions so YAML configuration can remain concise.

Key capabilities

  • Tap, hold, and release handling
  • Ramping (brightness, volume, cover travel)
  • Brightness- and volume-step logic
  • Fan speed stepping
  • Optional middle-button override for 5-button models
  • Support for one or multiple entities per device
  • Auto-detection of Pico layout (5-button, 4-button, 2-button, paddle)

How Configuration Works

All configuration is done in configuration.yaml instead of using a UI flow.
The structure is intentionally simple:

pico_link:
  defaults:
    step_pct: 10
    hold_time_ms: 300

  devices:
    - device_id: "12ab34cd56ef78..." (or name: Kitchen Lights Pico)
      type: 3BRL
      lights:
        - light.kitchen_lights
      middle_button:
        - action: light.turn_on
          data:
            color_name: red
          target:
            entity_id:
              - light.kitchen_lights

Defaults Layering

When building the final configuration for a device, the integration merges:

  1. Hardcoded dataclass defaults
  2. Integration level defaults (global)
  3. Device-level overrides

This reduces duplication and ensures consistent behavior across devices unless intentionally changed.


Domain Behavior Overview

The integration adapts actions based on the domain assigned to the device:

Lights

  • Tap on/off
  • Tap raise/lower → step brightness
  • Hold raise/lower → ramp brightness

Fans

  • Tap on/off
  • Tap raise/lower → step speed

Covers

  • Tap on → open
  • Tap off → close
  • Tap on/off while moving → stop
  • Tap middle → stop
  • Tap raise/lower → step position
  • Hold raise/lower → open/close until released

Media Players

  • Tap on → play/pause
  • Tap off → next track
  • Tap raise/lower → step volume

Execution Model

Internally, the integration uses:

  • Per-button press state tracking
  • Token-based hold lifecycle (prevents stray/overlapping tasks)
  • Async tasks for ramping/stepping
  • Automatic cancellation on release
  • Domain-aware action handlers

The design prioritizes consistency, determinism, and minimal latency from button press to action.


Where to Find the Code

Full source, documentation, examples, and ongoing changes are available here:

:backhand_index_pointing_right: https://github.com/smartqasa/pico-link

This integration is young. Issues and contributions are welcome.

4 Likes

EDIT: Turns out the Pico Link isn’t working at all for me. The apparent success from lights was because the Pico was mapped to control lights in the Lutron app. Removing that, and it’s not triggering the Pico Link automation in configuration.yaml at all.

The pico link controller is great. But I could use some help getting my integration working. I can control light on/off. But I can’t get it to command other non-light devices to power on/off.

Here’s the code. The light.turn_on / _off works. But the media player and remote commands don’t have any effect.

I’m using a Pico Paddle.

Can this be made to work? Thanks!


# pico link automations
pico_link:
  defaults:

  devices:
    # P2B Paddle — lights
    - name: Theater Switch
      type: P2B
      buttons: 
          on:
              actions:
                - action: remote.turn_on
                  metadata: {}
                  target:
                    entity_id: remote.jvc_projector
                  data: {}
                - action: media_player.turn_on
                  metadata: {}
                  target:
                    entity_id: media_player.marantz_av7702mkii
                  data: {}
                - action: light.turn_on
                  metadata: {}
                  target:
                    area_id: theater
                    data: {}
          off:
              actions:
                - action: remote.turn_off
                  metadata: {}
                  target:
                    entity_id: remote.jvc_projector
                  data: {}
                - action: media_player.turn_off
                  metadata: {}
                  target:
                    entity_id: media_player.marantz_av7702mkii
                  data: {}
                  mode: single
                - action: light.turn_off
                  metadata: {}
                  target:
                    area_id: theater
                    data: {}

I need pointers on the basic install. Pico Link doesn’t respond to anything.

The info says its files are to be installed to:
config/custom_components/pico_link/

But my Home Assistant install doesn’t have a config folder. Instead it’s installed here:
/homeassistant/custom_components/pico_link

Never mind. I couldn’t get Pico Link to work. I found an easier and native solution, at least for a simple Pico Paddle Switch:

In HA, go to Developer Tools, “subscribe” to this event and click the start listening button:
lutron_caseta_button_event

Press up to get that event info:

event_type: lutron_caseta_button_event
data:
  serial: 255912313
  type: PaddleSwitchPico
  button_number: 2
  leap_button_number: 0
  device_name: Switch
  device_id: ab38470d06c8319551eca64991fe5264
  area_name: SomeRoom
  button_type: "on"
  action: press
origin: LOCAL
time_fired: "2026-07-03T10:15:15.194623+00:00"
context:
  id: 01KFKQKCZTAUXENCFYQZ0J3EWT
  parent_id: null
  user_id: null

Create an Automation triggering on the device_id and button_number for the On and Off cases. Create a separate script if desired to separate the logic from the specific action.

alias: Pico Turn On
description: ""
triggers:
  - event_type: lutron_caseta_button_event
    event_data:
      action: press
      device_id: ab38470d06c8319551eca64991fe5264
    trigger: event
conditions:
  - condition: template
    value_template: "{{ trigger.event.data.button_number == 2 }}"
actions:
  - action: script.turn_on
    target:
      entity_id: script.pico_turn_on
mode: single

Repeat process for the Off button process.