Composite functions execute a sequence of different function types, passing data between them. They’re ideal for complex workflows that require multiple steps with different capabilities.
Configuration
function :
type : composite
sequence :
- type : function_type_1
# Configuration for first function
response_variable : result1
- type : function_type_2
# Configuration for second function (can use {{ result1 }})
List of functions to execute in order. Each can be any function type.
Variable name to store this step’s result for use in subsequent steps
Data Flow
Data flows between sequence steps using response_variable:
Step 1 executes
First function runs and produces a result - type : rest
resource : https://api.example.com/data
response_variable : api_data
Result stored
Result is stored in the variable name specified by response_variable
Step 2 accesses data
Subsequent steps can use the variable in templates - type : template
value_template : "Received: {{ api_data.count }} items"
Final result
The last step’s output becomes the function’s final result
Use Cases
Data Processing Fetch raw data and format it for presentation
Multi-step Workflows Execute complex sequences requiring different function types
Service + Template Call services and format their responses
Conditional Logic Use templates to process results conditionally
Best Practices
Use descriptive names for response_variable: response_variable : weather_data # Good
response_variable : result # Too generic
response_variable : r1 # Not descriptive
Each composite function should accomplish one logical task. If you need many steps, consider breaking into multiple functions. ✅ Good: 2-4 steps for a single purpose ❌ Bad: 10+ steps doing unrelated things
Add error handling in templates: {% if api_data is defined and api_data.success %}
{{ api_data.result }}
{% else %}
Error: Could not fetch data
{% endif %}
Test each step individually before combining:
Create individual functions for each step
Verify each works correctly
Combine into composite function
Test the complete sequence
Common Patterns
sequence :
- type : rest
resource : https://api.example.com/data
response_variable : raw_data
- type : template
value_template : "{{ raw_data | format_nicely }}"
sequence :
- type : script
sequence :
- service : domain.service
response_variable : service_result
- type : template
value_template : "{{ service_result.important_field }}"
Pattern 3: Multi-source Aggregation
sequence :
- type : rest
resource : https://api1.example.com
response_variable : data1
- type : rest
resource : https://api2.example.com
response_variable : data2
- type : template
value_template : > -
Combined data:
Source 1: {{ data1.value }}
Source 2: {{ data2.value }}
Pattern 4: Scrape + Process
sequence :
- type : scrape
resource : https://example.com
response_variable : scraped
sensor :
- name : price
select : ".price"
- type : template
value_template : > -
{% set clean_price = scraped.price | replace('$', '') | float %}
Price: ${{ "%.2f" | format(clean_price) }}
Debugging
Enable detailed logging:
logger :
logs :
custom_components.extended_openai_conversation : debug
Logs will show:
Each step’s input parameters
Each step’s output result
Variable assignments
Template rendering
Examples
Search and Play Music
Search for music, then play the first result:
- spec :
name : search_music
description : Use this function to search music
parameters :
type : object
properties :
query :
type : string
description : The search query
required :
- query
function :
type : composite
sequence :
- type : script
sequence :
- service : ytube_music_player.search
data :
entity_id : media_player.ytube_music_player
query : "{{ query }}"
- type : template
value_template : > -
media_content_type,media_content_id,title
{% for media in state_attr('sensor.ytube_music_player_extra', 'search') -%}
{{media.type}},{{media.id}},{{media.title}}
{% endfor%}
Get History with Formatting
Combine native get_history with template formatting:
- spec :
name : get_history
description : Retrieve historical data of specified entities.
parameters :
type : object
properties :
entity_ids :
type : array
items :
type : string
description : The entity id to filter.
start_time :
type : string
description : Start of the history period in "%Y-%m-%dT%H:%M:%S%z".
end_time :
type : string
description : End of the history period in "%Y-%m-%dT%H:%M:%S%z".
required :
- entity_ids
function :
type : composite
sequence :
- type : native
name : get_history
response_variable : history_result
- type : template
value_template : > -
{% set ns = namespace(result = [], list = []) %}
{% for item_list in history_result %}
{% set ns.list = [] %}
{% for item in item_list %}
{% set last_changed = item.last_changed | as_timestamp | timestamp_local if item.last_changed else None %}
{% set new_item = dict(item, last_changed=last_changed) %}
{% set ns.list = ns.list + [new_item] %}
{% endfor %}
{% set ns.result = ns.result + [ns.list] %}
{% endfor %}
{{ ns.result }}
Fetch and Process External Data
Get data from API and format it:
- spec :
name : get_weather_detailed
description : Get detailed weather information
parameters :
type : object
properties :
city :
type : string
description : City name
required :
- city
function :
type : composite
sequence :
- type : rest
resource : "https://wttr.in/{{ city }}?format=j1"
response_variable : weather_data
- type : template
value_template : > -
Weather in {{ city }}:
Current: {{ weather_data.current_condition[0].temp_C }}°C, {{ weather_data.current_condition[0].weatherDesc[0].value }}
Humidity: {{ weather_data.current_condition[0].humidity }}%
Wind: {{ weather_data.current_condition[0].windspeedKmph }} km/h
3-Day Forecast:
{% for day in weather_data.weather[:3] %}
{{ day.date }}: {{ day.mintempC }}-{{ day.maxtempC }}°C
{% endfor %}
Next Steps