Custom Automations
Pivot already handles common controls like brightness, volume and toggles out of the box, but because every press and turn also fires an event in Home Assistant, Pivot can become much more than a dial for default controls.
These examples show how Pivot can be extended into a more flexible input device — from colour control and scene scrubbing to sensor gauges, media shortcuts and context-aware button actions. Some examples simply add feedback, like changing the LED ring colour, while others completely repurpose the dial or button to do something new.
Each example includes:
- a quick explanation of the default Pivot behaviour
- what the automation changes
- an importable blueprint
- a raw YAML version you can adapt to your own setup
All blueprints include a built-in guard: if the entity configured in the blueprint is not currently assigned to the bank, the automation does nothing. That means you can reassign banks freely without needing to disable automations first.
For the full list of event fields, see the Events section of the Integration page.
Some examples gently extend Pivot’s native behaviour. Others completely change what a bank does. Start with the ones that match how you already use Pivot, then branch into the more custom setups once you’re comfortable.
| Automation | What it changes |
|---|---|
| Colour control | Uses the dial for colour temperature or hue instead of brightness, while press still toggles the light |
| Climate control | Adds LED ring colour feedback to reflect the thermostat set temperature |
| Button press with configurable action | Runs a custom action on button press while leaving dial control unchanged |
| Media player volume and power toggle | Uses the dial for volume and single press for TV power toggle |
| Scene scrubbing | Uses the dial to browse between scenes and the LED ring to preview the current selection |
| Sensor gauge | Displays a numeric value on the dial without allowing the source entity to be controlled |
| Light brightness and toggle | Uses automation to provide dial brightness control and press toggle for a light or light group |
Colour control — dial adjusts colour temperature or hue, press toggles light
Default behaviour
When a light is assigned directly to a bank, the knob adjusts brightness and a single press toggles the light on or off.
Automation behaviour
This automation keeps the button behaviour the same, but repurposes the dial for colour control instead — either colour temperature (cool to warm) or hue (across the colour wheel).
Why use it
Great for lamps and accent lighting where colour matters more than brightness, or where brightness is already set elsewhere.
Assign an input_number helper (range 0–100) to the bank. The automation translates the dial position into the appropriate colour value for your light, and can also keep the helper in sync if the light changes from elsewhere.
An optional Sync LED ring colour setting lets the ring reflect the light’s current colour. In colour temperature mode, it fades from cool blue to warm amber. In hue mode, it follows the light’s hue directly.
Create a helper: Settings → Devices & Services → Helpers → Number, with a range of 0–100 and step 1. Then assign it to the bank on your device.
Blueprint
Blueprint YAML
blueprint:
name: Pivot - Colour Control
description: >
Control a light's colour temperature or hue with the Pivot dial via an input_number helper.
Single press toggles the light. Dial position stays in sync with the light.
Optionally syncs the LED ring colour to match the light in both colour temperature and hue modes.
domain: automation
input:
suffix:
name: Device suffix
description: The suffix of your Pivot device (e.g. ha_voice_lounge)
selector:
text: {}
bank:
name: Bank number
description: The bank number to listen on (1–4)
selector:
number:
min: 1
max: 4
mode: box
input_number_entity:
name: Input number helper
description: The input_number entity assigned to this bank (range 0–100)
selector:
entity:
domain: input_number
light_entity:
name: Light
description: The light to control
selector:
entity:
domain: light
control_mode:
name: Control mode
description: >
Colour temperature adjusts warmth (cool to warm).
Hue sweeps through the colour wheel at full saturation.
default: colour_temperature
selector:
select:
options:
- label: Colour temperature
value: colour_temperature
- label: Hue
value: hue
sync_ring_colour:
name: Sync LED ring colour
description: >
When enabled, the LED ring colour updates to match the light's current colour.
In colour temperature mode, the ring fades from cool blue to warm amber.
In hue mode, the ring matches the light's current hue.
default: false
selector:
boolean:
variables:
suffix_var: !input suffix
bank_var: !input bank
triggers:
- trigger: homeassistant
event: start
id: sync
- trigger: state
entity_id: !input input_number_entity
id: dial
- trigger: event
event_type: pivot_button_press
event_data:
suffix: !input suffix
bank: !input bank
press_type: single_press
id: press
- trigger: state
entity_id: !input light_entity
id: sync
actions:
- variables:
light_entity: !input light_entity
input_number_entity: !input input_number_entity
control_mode: !input control_mode
sync_ring_colour: !input sync_ring_colour
suffix_var: !input suffix
bank_var: !input bank
percent: "{{ states(input_number_entity) | float(0) }}"
min_mired: "{{ state_attr(light_entity, 'min_mireds') | float(153) }}"
max_mired: "{{ state_attr(light_entity, 'max_mireds') | float(500) }}"
target_kelvin: >-
{{ (1000000 / ((min_mired | int) + ((percent / 100) * ((max_mired | int)
- (min_mired | int))))) | round(0) | int }}
current_mired: "{{ state_attr(light_entity, 'color_temp') | float(0) }}"
sync_percent_ct: >-
{{ (((current_mired - min_mired) / (max_mired - min_mired)) * 100) | round(0) }}
target_hue: "{{ (percent / 100 * 360) | int }}"
current_hue: "{{ (state_attr(light_entity, 'hs_color') or [0, 0])[0] | float(0) }}"
sync_percent_hue: "{{ (current_hue / 360 * 100) | round(0) }}"
target_hex: >-
{% set h = (percent / 100 * 360) | float %}
{% set ns = namespace(r=0.0, g=0.0, b=0.0) %}
{% set x = 1.0 - ((h / 60.0) % 2.0 - 1.0) | abs %}
{% if h < 60 %}{% set ns.r = 1.0 %}{% set ns.g = x %}
{% elif h < 120 %}{% set ns.r = x %}{% set ns.g = 1.0 %}
{% elif h < 180 %}{% set ns.g = 1.0 %}{% set ns.b = x %}
{% elif h < 240 %}{% set ns.g = x %}{% set ns.b = 1.0 %}
{% elif h < 300 %}{% set ns.r = x %}{% set ns.b = 1.0 %}
{% else %}{% set ns.r = 1.0 %}{% set ns.b = x %}{% endif %}
{{ '#%02x%02x%02x' | format((ns.r * 255) | round | int, (ns.g * 255) | round | int, (ns.b * 255) | round | int) }}
current_hex: >-
{% set h = (state_attr(light_entity, 'hs_color') or [0, 0])[0] | float %}
{% set ns = namespace(r=0.0, g=0.0, b=0.0) %}
{% set x = 1.0 - ((h / 60.0) % 2.0 - 1.0) | abs %}
{% if h < 60 %}{% set ns.r = 1.0 %}{% set ns.g = x %}
{% elif h < 120 %}{% set ns.r = x %}{% set ns.g = 1.0 %}
{% elif h < 180 %}{% set ns.g = 1.0 %}{% set ns.b = x %}
{% elif h < 240 %}{% set ns.g = x %}{% set ns.b = 1.0 %}
{% elif h < 300 %}{% set ns.r = x %}{% set ns.b = 1.0 %}
{% else %}{% set ns.r = 1.0 %}{% set ns.b = x %}{% endif %}
{{ '#%02x%02x%02x' | format((ns.r * 255) | round | int, (ns.g * 255) | round | int, (ns.b * 255) | round | int) }}
ct_ring_hex: >-
{% set rgb = state_attr(light_entity, 'rgb_color') or [255, 255, 255] %}
{{ '#%02x%02x%02x' | format(rgb[0] | int, rgb[1] | int, rgb[2] | int) }}
- condition: template
value_template: "{{ states('text.' ~ suffix_var ~ '_bank_' ~ bank_var ~ '_entity') == input_number_entity }}"
- choose:
- conditions:
- condition: trigger
id: dial
- condition: template
value_template: "{{ control_mode == 'colour_temperature' }}"
- condition: template
value_template: "{{ (trigger.to_state.state | float | round(0) | int) != (sync_percent_ct | round(0) | int) }}"
sequence:
- action: light.turn_on
target:
entity_id: !input light_entity
data:
color_temp_kelvin: "{{ target_kelvin | int }}"
- if:
- condition: template
value_template: "{{ sync_ring_colour }}"
then:
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_color"
data:
value: "{{ ct_ring_hex }}"
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_configured_color"
data:
value: "{{ ct_ring_hex }}"
- conditions:
- condition: trigger
id: dial
- condition: template
value_template: "{{ control_mode == 'hue' }}"
- condition: template
value_template: "{{ (trigger.to_state.state | float | round(0) | int) != (sync_percent_hue | round(0) | int) }}"
sequence:
- action: light.turn_on
target:
entity_id: !input light_entity
data:
hs_color:
- "{{ target_hue }}"
- 100
- if:
- condition: template
value_template: "{{ sync_ring_colour }}"
then:
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_color"
data:
value: "{{ target_hex }}"
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_configured_color"
data:
value: "{{ target_hex }}"
- conditions:
- condition: trigger
id: press
sequence:
- action: light.toggle
target:
entity_id: !input light_entity
- conditions:
- condition: trigger
id: sync
- condition: template
value_template: "{{ control_mode == 'colour_temperature' and current_mired > 0 and max_mired > min_mired }}"
sequence:
- action: input_number.set_value
target:
entity_id: !input input_number_entity
data:
value: "{{ [[sync_percent_ct, 0] | max, 100] | min }}"
- if:
- condition: template
value_template: "{{ sync_ring_colour }}"
then:
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_color"
data:
value: "{{ ct_ring_hex }}"
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_configured_color"
data:
value: "{{ ct_ring_hex }}"
- conditions:
- condition: trigger
id: sync
- condition: template
value_template: "{{ control_mode == 'hue' and state_attr(light_entity, 'hs_color') is not none }}"
sequence:
- action: input_number.set_value
target:
entity_id: !input input_number_entity
data:
value: "{{ [[sync_percent_hue, 0] | max, 100] | min }}"
- if:
- condition: template
value_template: "{{ sync_ring_colour }}"
then:
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_color"
data:
value: "{{ current_hex }}"
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_configured_color"
data:
value: "{{ current_hex }}"
mode: single
Raw automation examples
Colour temperature
alias: Pivot - Study Lamp Warmth
triggers:
- trigger: state
entity_id: input_number.study_lamp_warmth
id: dial
- trigger: event
event_type: pivot_button_press
event_data:
suffix: ha_voice_lounge
bank: 2
press_type: single_press
id: press
- trigger: state
entity_id: light.study_lamp
id: sync
actions:
- variables:
percent: "{{ states('input_number.study_lamp_warmth') | float(0) }}"
min_mired: "{{ state_attr('light.study_lamp', 'min_mireds') | float(153) }}"
max_mired: "{{ state_attr('light.study_lamp', 'max_mireds') | float(500) }}"
target_kelvin: >-
{{ (1000000 / ((min_mired | int) + ((percent / 100) * ((max_mired | int)
- (min_mired | int))))) | round(0) | int }}
current_mired: "{{ state_attr('light.study_lamp', 'color_temp') | float(0) }}"
sync_percent_ct: >-
{{ (((current_mired - min_mired) / (max_mired - min_mired)) * 100) | round(0) }}
- choose:
- conditions:
- condition: trigger
id: dial
- condition: template
value_template: "{{ (trigger.to_state.state | float | round(0) | int) != (sync_percent_ct | round(0) | int) }}"
sequence:
- action: light.turn_on
target:
entity_id: light.study_lamp
data:
color_temp_kelvin: "{{ target_kelvin | int }}"
- conditions:
- condition: trigger
id: press
sequence:
- action: light.toggle
target:
entity_id: light.study_lamp
- conditions:
- condition: trigger
id: sync
- condition: template
value_template: "{{ current_mired > 0 and max_mired > min_mired }}"
sequence:
- action: input_number.set_value
target:
entity_id: input_number.study_lamp_warmth
data:
value: "{{ [[sync_percent_ct, 0] | max, 100] | min }}"
mode: single
Hue
alias: Pivot - Desk Light Hue
triggers:
- trigger: state
entity_id: input_number.desk_light_hue
id: dial
- trigger: event
event_type: pivot_button_press
event_data:
suffix: ha_voice_lounge
bank: 3
press_type: single_press
id: press
- trigger: state
entity_id: light.desk_light
id: sync
actions:
- variables:
percent: "{{ states('input_number.desk_light_hue') | float(0) }}"
target_hue: "{{ (percent / 100 * 360) | int }}"
current_hue: "{{ (state_attr('light.desk_light', 'hs_color') | default([0, 0]))[0] | float(0) }}"
sync_percent_hue: "{{ (current_hue / 360 * 100) | round(0) }}"
target_hex: >-
{% set h = (percent / 100 * 360) | float %}
{% set ns = namespace(r=0.0, g=0.0, b=0.0) %}
{% set x = 1.0 - ((h / 60.0) % 2.0 - 1.0) | abs %}
{% if h < 60 %}{% set ns.r = 1.0 %}{% set ns.g = x %}
{% elif h < 120 %}{% set ns.r = x %}{% set ns.g = 1.0 %}
{% elif h < 180 %}{% set ns.g = 1.0 %}{% set ns.b = x %}
{% elif h < 240 %}{% set ns.g = x %}{% set ns.b = 1.0 %}
{% elif h < 300 %}{% set ns.r = x %}{% set ns.b = 1.0 %}
{% else %}{% set ns.r = 1.0 %}{% set ns.b = x %}{% endif %}
{{ '#%02x%02x%02x' | format((ns.r * 255) | round | int, (ns.g * 255) | round | int, (ns.b * 255) | round | int) }}
current_hex: >-
{% set h = current_hue %}
{% set ns = namespace(r=0.0, g=0.0, b=0.0) %}
{% set x = 1.0 - ((h / 60.0) % 2.0 - 1.0) | abs %}
{% if h < 60 %}{% set ns.r = 1.0 %}{% set ns.g = x %}
{% elif h < 120 %}{% set ns.r = x %}{% set ns.g = 1.0 %}
{% elif h < 180 %}{% set ns.g = 1.0 %}{% set ns.b = x %}
{% elif h < 240 %}{% set ns.g = x %}{% set ns.b = 1.0 %}
{% elif h < 300 %}{% set ns.r = x %}{% set ns.b = 1.0 %}
{% else %}{% set ns.r = 1.0 %}{% set ns.b = x %}{% endif %}
{{ '#%02x%02x%02x' | format((ns.r * 255) | round | int, (ns.g * 255) | round | int, (ns.b * 255) | round | int) }}
- choose:
- conditions:
- condition: trigger
id: dial
- condition: template
value_template: "{{ (trigger.to_state.state | float | round(0) | int) != (sync_percent_hue | round(0) | int) }}"
sequence:
- action: light.turn_on
target:
entity_id: light.desk_light
data:
hs_color:
- "{{ target_hue }}"
- 100
- action: text.set_value
target:
entity_id: text.ha_voice_lounge_bank_3_color
data:
value: "{{ target_hex }}"
- action: text.set_value
target:
entity_id: text.ha_voice_lounge_bank_3_configured_color
data:
value: "{{ target_hex }}"
- conditions:
- condition: trigger
id: press
sequence:
- action: light.toggle
target:
entity_id: light.desk_light
- conditions:
- condition: trigger
id: sync
- condition: template
value_template: "{{ state_attr('light.desk_light', 'hs_color') is not none }}"
sequence:
- action: input_number.set_value
target:
entity_id: input_number.desk_light_hue
data:
value: "{{ [[sync_percent_hue, 0] | max, 100] | min }}"
- action: text.set_value
target:
entity_id: text.ha_voice_lounge_bank_3_color
data:
value: "{{ current_hex }}"
- action: text.set_value
target:
entity_id: text.ha_voice_lounge_bank_3_configured_color
data:
value: "{{ current_hex }}"
mode: single
Climate control — dial sets temperature, press toggles on/off
Default behaviour
When a climate entity is assigned to a bank, Pivot already handles temperature adjustment with the dial and on/off control with a press.
Automation behaviour
This automation does not change the control behaviour. Instead, it adds richer LED feedback by mapping the thermostat set temperature to a colour range on the ring.
Why use it
It makes climate control feel more physical at a glance — cooler settings can look blue, warmer settings can fade toward orange or red.
No helper entities are required. Assign a climate entity directly to a bank as normal, then use this blueprint to colour the LED ring based on the current set temperature.
The ring interpolates smoothly across eight configurable colour stops distributed evenly between your minimum and maximum temperature.
Works with both Celsius and Fahrenheit — just set temp_min and temp_max in whichever unit Home Assistant uses.
Blueprint
Blueprint YAML
blueprint:
name: Pivot - Climate Control
description: >
Colours the LED ring of a Pivot bank based on the set temperature of a
climate entity. Assign the climate entity directly to the bank — the Pivot
integration handles temperature control and on/off toggle natively. This
blueprint only manages the ring colour, smoothly interpolating across eight
colour stops that are evenly distributed between your configured minimum and
maximum temperatures.
The climate entity is read automatically from the bank assignment — no need
to specify it here.
Works with both Celsius and Fahrenheit. Set temp_min and temp_max in whichever
unit your Home Assistant uses (e.g. 16 and 30 for °C, or 61 and 86 for °F).
The colour interpolation is percentage-based and fully unit-agnostic.
domain: automation
input:
suffix:
name: Device suffix
description: The suffix of your Pivot device (e.g. ha_voice_lounge)
selector:
text: {}
bank:
name: Bank number
description: The bank number this climate entity is assigned to (1–4)
selector:
number:
min: 1
max: 4
mode: box
temp_min:
name: Temperature minimum
description: >
The temperature mapped to 0% on the dial. Use your HA unit — °C or °F
(e.g. 16 for Celsius, 61 for Fahrenheit).
default: 16
selector:
number:
min: -40
max: 120
step: 0.5
mode: box
temp_max:
name: Temperature maximum
description: >
The temperature mapped to 100% on the dial. Use your HA unit — °C or °F
(e.g. 30 for Celsius, 86 for Fahrenheit).
default: 30
selector:
number:
min: -40
max: 120
step: 0.5
mode: box
color_1:
name: Colour 1 — coldest (0%)
description: Colour shown at or below the minimum temperature
default: [77, 92, 224]
selector:
color_rgb: {}
color_2:
name: Colour 2 — (~14%)
default: [75, 176, 208]
selector:
color_rgb: {}
color_3:
name: Colour 3 — (~29%)
default: [77, 196, 168]
selector:
color_rgb: {}
color_4:
name: Colour 4 — (~43%)
default: [61, 232, 112]
selector:
color_rgb: {}
color_5:
name: Colour 5 — (~57%)
default: [244, 224, 28]
selector:
color_rgb: {}
color_6:
name: Colour 6 — (~71%)
default: [240, 128, 48]
selector:
color_rgb: {}
color_7:
name: Colour 7 — (~86%)
default: [216, 60, 32]
selector:
color_rgb: {}
color_8:
name: Colour 8 — hottest (100%)
description: Colour shown at or above the maximum temperature
default: [190, 46, 30]
selector:
color_rgb: {}
variables:
suffix_var: !input suffix
bank_var: !input bank
triggers:
- trigger: template
value_template: >
{{ state_attr(states('text.' ~ suffix_var ~ '_bank_' ~ bank_var ~ '_entity'), 'temperature') | string }}
id: climate
- trigger: event
event_type: pivot_knob_turn
event_data:
suffix: !input suffix
bank: !input bank
id: knob
actions:
- variables:
climate_entity: "{{ states('text.' ~ suffix_var ~ '_bank_' ~ bank_var ~ '_entity') }}"
- condition: template
value_template: "{{ climate_entity.startswith('climate.') }}"
- variables:
temp_min: !input temp_min
temp_max: !input temp_max
color_1: !input color_1
color_2: !input color_2
color_3: !input color_3
color_4: !input color_4
color_5: !input color_5
color_6: !input color_6
color_7: !input color_7
color_8: !input color_8
set_temp: >-
{% if trigger.id == 'knob' %}
{{ temp_min + (trigger.event.data.value | float(0) / 100) * (temp_max - temp_min) }}
{% else %}
{{ state_attr(climate_entity, 'temperature') | float(temp_min) }}
{% endif %}
ring_color: >-
{% set pct = [[(set_temp | float - temp_min) / (temp_max - temp_min) * 100, 0] | max, 100] | min %}
{% set sw = 100 / 7 %}
{% set seg = [[((pct / sw) | int), 0] | max, 6] | min %}
{% set frac = (pct - seg * sw) / sw %}
{% set ns = namespace(c0=[0, 0, 0], c1=[0, 0, 0]) %}
{% if seg == 0 %}{% set ns.c0 = color_1 %}{% set ns.c1 = color_2 %}
{% elif seg == 1 %}{% set ns.c0 = color_2 %}{% set ns.c1 = color_3 %}
{% elif seg == 2 %}{% set ns.c0 = color_3 %}{% set ns.c1 = color_4 %}
{% elif seg == 3 %}{% set ns.c0 = color_4 %}{% set ns.c1 = color_5 %}
{% elif seg == 4 %}{% set ns.c0 = color_5 %}{% set ns.c1 = color_6 %}
{% elif seg == 5 %}{% set ns.c0 = color_6 %}{% set ns.c1 = color_7 %}
{% else %}{% set ns.c0 = color_7 %}{% set ns.c1 = color_8 %}{% endif %}
{% set r = (ns.c0[0] + frac * (ns.c1[0] - ns.c0[0])) | int %}
{% set g = (ns.c0[1] + frac * (ns.c1[1] - ns.c0[1])) | int %}
{% set b = (ns.c0[2] + frac * (ns.c1[2] - ns.c0[2])) | int %}
{{ '#%02x%02x%02x' | format(r, g, b) }}
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_color"
data:
value: "{{ ring_color }}"
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_configured_color"
data:
value: "{{ ring_color }}"
mode: queued
max: 5
Button press with configurable action — e.g. dial controls volume, press to play/pause media
Default behaviour
A bank normally uses its built-in button action for the currently assigned entity.
Automation behaviour
This automation lets the button press do something completely custom instead, while the dial continues controlling the assigned bank value as normal.
Why use it
Useful when the thing you want on press is related to the bank, but not the entity’s native toggle action — for example, pausing your computer while the dial controls system volume.
You can choose the press type and action, and optionally require that a specific entity is currently assigned to the bank. That makes the automation context-aware: reassign the bank and the custom action stops firing automatically.
Blueprint
Blueprint YAML
blueprint:
name: Pivot - Button Press Action
description: >
Run a configurable action on button press for a specific Pivot device and bank,
with an optional check that a particular entity is assigned to that bank.
domain: automation
input:
suffix:
name: Device suffix
description: The suffix of your Pivot device (e.g. ha_voice_lounge)
selector:
text: {}
bank:
name: Bank number
description: The bank number to listen on (1–4)
selector:
number:
min: 1
max: 4
mode: box
press_type:
name: Press type
description: Which press type triggers the action
default: single_press
selector:
select:
options:
- single_press
- double_press
- triple_press
- long_press
assigned_entity:
name: Assigned entity (optional)
description: >
Only fire the action if this entity is currently assigned to the bank.
Leave blank to fire regardless of what is assigned.
default: ""
selector:
text: {}
action:
name: Action
description: Action to run when the button is pressed
selector:
action: {}
triggers:
- trigger: event
event_type: pivot_button_press
event_data:
suffix: !input suffix
bank: !input bank
press_type: !input press_type
conditions:
- condition: template
value_template: >
{% set entity = 'text.' ~ suffix ~ '_bank_' ~ bank ~ '_entity' %}
{% set assigned = assigned_entity %}
{{ assigned == '' or states(entity) == assigned }}
actions:
- sequence: !input action
mode: single
Raw automation example
Raw automation example
alias: Pivot - Computer Play/Pause
triggers:
- trigger: event
event_type: pivot_button_press
event_data:
suffix: ha_voice_lounge
bank: 1
press_type: single_press
conditions:
- condition: template
value_template: >
{{ states('text.ha_voice_lounge_bank_1_entity') == 'input_number.computer_volume' }}
actions:
- action: shell_command.music_playpause
mode: single
Media player volume and power toggle — dial controls volume, press toggles TV on/off
Default behaviour
When a media player is assigned to a bank, the knob adjusts volume and a single press sends play/pause.
Automation behaviour
This automation keeps volume on the dial, but changes the press action to toggle power instead — better suited to TV-style use.
Why use it
For televisions, power control is usually more useful than play/pause from the bank itself.
Assign your TV entity to the bank as normal. The automation reads the assigned media player automatically and adds power toggle behaviour on single press.
The standard play/pause action may still fire alongside the power toggle, but for most TV entities this is harmless. If you want separate play/pause control for streaming apps, it is usually better to assign the streaming device to a different bank.
Blueprint
Blueprint YAML
blueprint:
name: Pivot - Media Player Volume & Power Toggle
description: >
Control a TV's volume with the Pivot dial and toggle power on single press.
Assign your TV entity to the bank as normal — the media player entity is read
automatically from the bank assignment. Single press will toggle power alongside
the native play/pause — in practice the play/pause is harmless for a TV entity.
domain: automation
input:
suffix:
name: Device suffix
description: The suffix of your Pivot device (e.g. ha_voice_lounge)
selector:
text: {}
bank:
name: Bank number
description: The bank number to listen on (1–4)
selector:
number:
min: 1
max: 4
mode: box
variables:
suffix_var: !input suffix
bank_var: !input bank
triggers:
- trigger: event
event_type: pivot_knob_turn
event_data:
suffix: !input suffix
bank: !input bank
id: knob
- trigger: event
event_type: pivot_button_press
event_data:
suffix: !input suffix
bank: !input bank
press_type: single_press
id: press
actions:
- variables:
media_player_entity: "{{ states('text.' ~ suffix_var ~ '_bank_' ~ bank_var ~ '_entity') }}"
- condition: template
value_template: "{{ media_player_entity.startswith('media_player.') }}"
- choose:
- conditions:
- condition: trigger
id: knob
sequence:
- action: media_player.volume_set
target:
entity_id: "{{ media_player_entity }}"
data:
volume_level: "{{ trigger.event.data.value / 100 }}"
- conditions:
- condition: trigger
id: press
sequence:
- action: media_player.toggle
target:
entity_id: "{{ media_player_entity }}"
mode: single
Raw automation example
Raw automation example
alias: Pivot - Living Room TV
triggers:
- trigger: event
event_type: pivot_knob_turn
event_data:
suffix: ha_voice_lounge
bank: 3
id: knob
- trigger: event
event_type: pivot_button_press
event_data:
suffix: ha_voice_lounge
bank: 3
press_type: single_press
id: press
actions:
- choose:
- conditions:
- condition: trigger
id: knob
sequence:
- action: media_player.volume_set
target:
entity_id: media_player.living_room_tv
data:
volume_level: "{{ trigger.event.data.value / 100 }}"
- conditions:
- condition: trigger
id: press
sequence:
- action: media_player.toggle
target:
entity_id: media_player.living_room_tv
mode: single
Scene scrubbing — dial selects a slot, press toggles it
Default behaviour
If a light is assigned to a bank, the knob adjusts brightness and the button toggles the light.
Automation behaviour
This automation divides the dial’s 0–100 range into four equal zones, each mapped to a different entity. Turning the dial updates the LED ring colour to show which zone you’re in. Pressing the button toggles the entity in the current zone. Works with scenes, lights, switches, or anything Home Assistant can turn on or toggle. Slots 2–4 are optional.
Why use it
A tactile way to switch between a small set of room moods or presets — turn to the one you want, press to activate it.
The dial’s 0–100 range is split into four equal bands (0–25%, 25–50%, 50–75%, 75–100%). Assign an entity to as many slots as you need — minimum one.
Create a helper: Settings → Devices & Services → Helpers → Number, with a range of 0–100 and step 1. Assign it to the bank on your device.
Blueprint
Blueprint YAML
blueprint:
name: Pivot - Scene Scrubbing
description: >
Map up to four entities across the dial's 0–100 range. Turning the dial
moves between four equal zones and the LED ring colour updates to show which
slot is active. Press to toggle the current slot's entity. Works with
scenes, lights, switches, or anything Home Assistant can turn on or toggle.
Slots 2–4 are optional — zones with no entity assigned are skipped on press.
Assign an input_number helper (range 0–100) to the bank.
domain: automation
input:
suffix:
name: Device suffix
description: The suffix of your Pivot device (e.g. ha_voice_lounge)
selector:
text: {}
bank:
name: Bank number
description: The bank number to listen on (1–4)
selector:
number:
min: 1
max: 4
mode: box
input_number_entity:
name: Input number helper
description: The input_number entity assigned to this bank (range 0–100)
selector:
entity:
domain: input_number
scene_1:
name: Entity 1 (0–25%)
selector:
entity: {}
scene_2:
name: Entity 2 (25–50%)
description: Optional
default:
selector:
entity: {}
scene_3:
name: Entity 3 (50–75%)
description: Optional
default:
selector:
entity: {}
scene_4:
name: Entity 4 (75–100%)
description: Optional
default:
selector:
entity: {}
color_1:
name: Colour — Entity 1
default: [40, 137, 255]
selector:
color_rgb: {}
color_2:
name: Colour — Entity 2
default: [255, 125, 25]
selector:
color_rgb: {}
color_3:
name: Colour — Entity 3
default: [151, 255, 61]
selector:
color_rgb: {}
color_4:
name: Colour — Entity 4
default: [200, 0, 255]
selector:
color_rgb: {}
variables:
suffix_var: !input suffix
bank_var: !input bank
triggers:
- trigger: homeassistant
event: start
id: start
- trigger: state
entity_id: !input input_number_entity
id: dial
- trigger: event
event_type: pivot_button_press
event_data:
suffix: !input suffix
bank: !input bank
press_type: single_press
id: press
actions:
- variables:
input_number_entity: !input input_number_entity
suffix_var: !input suffix
bank_var: !input bank
scene_1: !input scene_1
scene_2: !input scene_2
scene_3: !input scene_3
scene_4: !input scene_4
color_1: !input color_1
color_2: !input color_2
color_3: !input color_3
color_4: !input color_4
val: "{{ states(input_number_entity) | float(0) }}"
current_slot: "{{ [(val / 25) | int, 3] | min }}"
selected_entity: >-
{% set entities = [scene_1, scene_2, scene_3, scene_4] %}
{% set e = entities[current_slot | int] %}
{{ e if e is not none and e != '' else scene_1 }}
ring_color: >-
{% set c = [color_1, color_2, color_3, color_4][current_slot | int] %}
{{ '#%02x%02x%02x' | format(c[0] | int, c[1] | int, c[2] | int) }}
- condition: template
value_template: "{{ states('text.' ~ suffix_var ~ '_bank_' ~ bank_var ~ '_entity') == input_number_entity }}"
- choose:
- conditions:
- condition: trigger
id: dial
sequence:
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_color"
data:
value: "{{ ring_color }}"
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_configured_color"
data:
value: "{{ ring_color }}"
- conditions:
- condition: trigger
id: press
sequence:
- condition: template
value_template: "{{ selected_entity is not none and selected_entity != '' }}"
- action: homeassistant.toggle
target:
entity_id: "{{ selected_entity }}"
- conditions:
- condition: trigger
id: start
sequence:
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_color"
data:
value: "{{ ring_color }}"
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_configured_color"
data:
value: "{{ ring_color }}"
mode: single
Raw automation example
Raw automation example
alias: Pivot - Living Room Scenes
triggers:
- trigger: state
entity_id: input_number.living_room_scene
id: dial
- trigger: event
event_type: pivot_button_press
event_data:
suffix: ha_voice_lounge
bank: 1
press_type: single_press
id: press
actions:
- variables:
val: "{{ states('input_number.living_room_scene') | float(0) }}"
current_slot: "{{ [(val / 25) | int, 3] | min }}"
selected_entity: >-
{% set entities = ['scene.relax', 'scene.evening', 'scene.bright', 'scene.focus'] %}
{{ entities[current_slot | int] }}
ring_color: >-
{% set colors = ['#2889ff', '#ff7d19', '#97ff3d', '#c800ff'] %}
{{ colors[current_slot | int] }}
- choose:
- conditions:
- condition: trigger
id: dial
sequence:
- action: text.set_value
target:
entity_id: text.ha_voice_lounge_bank_1_color
data:
value: "{{ ring_color }}"
- action: text.set_value
target:
entity_id: text.ha_voice_lounge_bank_1_configured_color
data:
value: "{{ ring_color }}"
- conditions:
- condition: trigger
id: press
sequence:
- action: homeassistant.toggle
target:
entity_id: "{{ selected_entity }}"
mode: single
How it works: The
input_numbertracks the dial’s 0–100 position. Each state change maps the value to one of four 25% zones and updates the ring colour. Pressing callshomeassistant.toggleon the entity assigned to the current zone — turning it on if it’s off, and off if it’s on. Ring colour syncs to the current position on HA startup.
Sensor gauge — display any numeric value on the dial
Default behaviour
A bank normally controls the assigned entity by writing values back to it when the dial is turned.
Automation behaviour
This automation turns the bank into a read-only gauge. Pivot follows a numeric value and displays it physically, but the dial itself does not control the source.
Why use it
A nice way to surface live values like fuel level, battery charge, washing machine progress or a thermostat target on a physical dial.
This is always one-way. The automation only writes to the input_number helper assigned to the bank — never back to the source entity. If the dial is turned, it snaps back to the real value.
The LED ring can also optionally reflect the current percentage using six configurable colour bands.
Blueprint
Blueprint YAML
blueprint:
name: Pivot - Sensor Gauge
description: >
Map any numeric sensor, input_number, or number entity to a Pivot bank for
display only. Always one-way — the source entity is never written to. The dial
position reflects the value scaled between a configurable min and max. If the
dial is accidentally turned, it automatically reverts to the source value.
Optionally colours the LED ring based on the current percentage.
domain: automation
input:
sensor_entity:
name: Source entity
description: The sensor, input_number, or number entity to monitor (e.g. a fuel level, battery, tank sensor, or any numeric helper)
selector:
entity:
domain:
- sensor
- input_number
- number
input_number_entity:
name: Input number helper
description: The input_number entity assigned to this bank (range 0–100)
selector:
entity:
domain: input_number
sensor_min:
name: Sensor minimum
description: The sensor value that corresponds to 0% on the dial
default: 0
selector:
number:
min: -9999
max: 9999
step: 0.1
mode: box
sensor_max:
name: Sensor maximum
description: The sensor value that corresponds to 100% on the dial
default: 100
selector:
number:
min: -9999
max: 9999
step: 0.1
mode: box
suffix:
name: Device suffix
description: The suffix of your Pivot device (e.g. ha_voice_lounge)
selector:
text: {}
bank:
name: Bank number
description: The bank number this input_number is assigned to (1–4)
selector:
number:
min: 1
max: 4
mode: box
sync_ring_colour:
name: Sync LED ring colour
description: >
When enabled, the LED ring colour updates based on the current percentage
using the colour bands below.
default: true
selector:
boolean:
color_0_16:
name: Colour — 0 to 16%
default: [255, 69, 58]
selector:
color_rgb: {}
color_16_33:
name: Colour — 16 to 33%
default: [255, 122, 0]
selector:
color_rgb: {}
color_33_50:
name: Colour — 33 to 50%
default: [255, 159, 10]
selector:
color_rgb: {}
color_50_66:
name: Colour — 50 to 66%
default: [255, 214, 10]
selector:
color_rgb: {}
color_66_83:
name: Colour — 66 to 83%
default: [169, 220, 56]
selector:
color_rgb: {}
color_83_100:
name: Colour — 83 to 100%
default: [48, 209, 88]
selector:
color_rgb: {}
variables:
suffix_var: !input suffix
bank_var: !input bank
triggers:
- trigger: state
entity_id: !input sensor_entity
id: sensor
- trigger: state
entity_id: !input input_number_entity
id: number_changed
- trigger: event
event_type: pivot_knob_turn
event_data:
suffix: !input suffix
bank: !input bank
id: knob
actions:
- variables:
input_number_entity: !input input_number_entity
sensor_entity: !input sensor_entity
sensor_min: !input sensor_min
sensor_max: !input sensor_max
suffix_var: !input suffix
bank_var: !input bank
sync_ring_colour: !input sync_ring_colour
color_0_16: !input color_0_16
color_16_33: !input color_16_33
color_33_50: !input color_33_50
color_50_66: !input color_50_66
color_66_83: !input color_66_83
color_83_100: !input color_83_100
sensor_value: "{{ states(sensor_entity) | float(0) }}"
computed_percent: >-
{{ [[(sensor_value - sensor_min) / (sensor_max - sensor_min) * 100, 0]
| max, 100] | min | round(0) | int }}
current_number: "{{ states(input_number_entity) | float(-1) }}"
ring_color: >-
{% if computed_percent < 16 %}{% set c = color_0_16 %}
{% elif computed_percent < 33 %}{% set c = color_16_33 %}
{% elif computed_percent < 50 %}{% set c = color_33_50 %}
{% elif computed_percent < 66 %}{% set c = color_50_66 %}
{% elif computed_percent < 83 %}{% set c = color_66_83 %}
{% else %}{% set c = color_83_100 %}{% endif %}
{{ '#%02x%02x%02x' | format(c[0] | int, c[1] | int, c[2] | int) }}
- condition: template
value_template: "{{ states('text.' ~ suffix_var ~ '_bank_' ~ bank_var ~ '_entity') == input_number_entity }}"
- choose:
- conditions:
- condition: trigger
id: knob
sequence:
- action: input_number.set_value
target:
entity_id: !input input_number_entity
data:
value: "{{ computed_percent }}"
default:
- if:
- condition: template
value_template: "{{ computed_percent != current_number and states(sensor_entity) not in ('unknown', 'unavailable') }}"
then:
- action: input_number.set_value
target:
entity_id: !input input_number_entity
data:
value: "{{ computed_percent }}"
- if:
- condition: template
value_template: "{{ sync_ring_colour }}"
then:
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_color"
data:
value: "{{ ring_color }}"
- action: text.set_value
target:
entity_id: "text.{{ suffix_var }}_bank_{{ bank_var }}_configured_color"
data:
value: "{{ ring_color }}"
mode: single
Raw automation example
Raw automation example
alias: Pivot - Fuel Level
triggers:
- trigger: state
entity_id: sensor.car_fuel_level
id: sensor
- trigger: state
entity_id: input_number.fuel_gauge
id: number_changed
actions:
- variables:
sensor_value: "{{ states('sensor.car_fuel_level') | float(0) }}"
computed_percent: "{{ [[(sensor_value - 0) / (60 - 0) * 100, 0] | max, 100] | min | round(0) | int }}"
current_number: "{{ states('input_number.fuel_gauge') | float(-1) }}"
ring_color: >-
{% if computed_percent < 16 %}{% set c = [255, 69, 58] %}
{% elif computed_percent < 33 %}{% set c = [255, 122, 0] %}
{% elif computed_percent < 50 %}{% set c = [255, 159, 10] %}
{% elif computed_percent < 66 %}{% set c = [255, 214, 10] %}
{% elif computed_percent < 83 %}{% set c = [169, 220, 56] %}
{% else %}{% set c = [48, 209, 88] %}{% endif %}
{{ '#%02x%02x%02x' | format(c[0], c[1], c[2]) }}
- if:
- condition: template
value_template: "{{ computed_percent != current_number and states('sensor.car_fuel_level') not in ('unknown', 'unavailable') }}"
then:
- action: input_number.set_value
target:
entity_id: input_number.fuel_gauge
data:
value: "{{ computed_percent }}"
- action: text.set_value
target:
entity_id: text.ha_voice_lounge_bank_2_color
data:
value: "{{ ring_color }}"
- action: text.set_value
target:
entity_id: text.ha_voice_lounge_bank_2_configured_color
data:
value: "{{ ring_color }}"
mode: single
Light brightness and toggle — dial sets brightness, press toggles on/off
Default behaviour
Assigning a light directly to a bank already gives you brightness on the dial and toggle on press.
Automation behaviour
This reproduces that behaviour using an automation instead of relying on the built-in bank handling.
Why use it
Useful as a simple example, or when you want the same light-style control pattern for something Pivot would not normally handle directly, such as a light group.
Unlike the colour control example, this one uses the raw pivot_knob_turn event directly rather than an input_number helper. The dial value is passed straight through as a brightness percentage.
Blueprint
Blueprint YAML
blueprint:
name: Pivot - Light Brightness & Toggle
description: >
Control a light's brightness with the Pivot dial. Single press toggles the light on/off.
domain: automation
input:
suffix:
name: Device suffix
description: The suffix of your Pivot device (e.g. ha_voice_lounge)
selector:
text: {}
bank:
name: Bank number
description: The bank number to listen on (1–4)
selector:
number:
min: 1
max: 4
mode: box
light_entity:
name: Light
description: The light to control
selector:
entity:
domain: light
variables:
suffix_var: !input suffix
bank_var: !input bank
triggers:
- trigger: event
event_type: pivot_knob_turn
event_data:
suffix: !input suffix
bank: !input bank
id: knob
- trigger: event
event_type: pivot_button_press
event_data:
suffix: !input suffix
bank: !input bank
press_type: single_press
id: press
actions:
- variables:
light_entity: !input light_entity
- condition: template
value_template: "{{ states('text.' ~ suffix_var ~ '_bank_' ~ bank_var ~ '_entity') == light_entity }}"
- choose:
- conditions:
- condition: trigger
id: knob
sequence:
- action: light.turn_on
target:
entity_id: "{{ light_entity }}"
data:
brightness_pct: "{{ trigger.event.data.value }}"
- conditions:
- condition: trigger
id: press
sequence:
- action: light.toggle
target:
entity_id: "{{ light_entity }}"
mode: single
Raw automation example
Raw automation examples
alias: Pivot - Living Room Brightness
triggers:
- trigger: event
event_type: pivot_knob_turn
event_data:
suffix: ha_voice_lounge
bank: 1
actions:
- action: light.turn_on
target:
entity_id: light.living_room
data:
brightness_pct: "{{ trigger.event.data.value }}"
mode: single
alias: Pivot - Living Room Toggle
triggers:
- trigger: event
event_type: pivot_button_press
event_data:
suffix: ha_voice_lounge
bank: 1
press_type: single_press
actions:
- action: light.toggle
target:
entity_id: light.living_room
mode: single