Skip to main content

Migrating Template Sensors to Modern Syntax

Important Notice

The legacy platform: template syntax will stop working in Home Assistant version 2026.6 (June 2026). Home Assistant is already warning you, and you need to migrate to modern syntax.

How to Identify the Need to Migrate

Home Assistant alerts you to this issue in two ways:

1. Repairs Section Notifications

The most visible alert appears in Settings → System → Repairs, where you'll see a list of all deprecated template sensors:

Deprecated template sensor alerts in Repairs section

Each deprecated sensor is listed separately with the text "Deprecated template sensor" or "Deprecated template binary_sensor".

2. Log Warnings

Alternatively, you can find warnings directly in the Home Assistant logs (Settings → System → Logs), where you'll see specific details about the issue.


If you're seeing either of these warnings, you're in the right place. In this article, we'll show you how to easily migrate the legacy syntax to modern format.

What's Changing and Why

Home Assistant is gradually modernizing how template entities are defined. The old syntax was introduced years ago and had its limitations. Modern syntax brings:

  • More readable code - better structured and understandable
  • More options - trigger-based sensors, better control over updates
  • Unique ID - ability to edit via UI
  • Consistency - same syntax for all types of template entities
  • Better performance - more efficient processing

When to Migrate

If you have this syntax in your configuration files (typically configuration.yaml or in packages/), you need to migrate:

sensor:
- platform: template
sensors:
# ... your sensor definitions

or

binary_sensor:
- platform: template
sensors:
# ... your binary sensor definitions

Basic Migration Rules

Legacy SyntaxModern Syntax
friendly_name:name:
value_template:state:
icon_template:icon:
sensors: (list)Direct definition without nested level
In sensor: sectionIn template: section

Example 1: Simple Sensor - Temperature Conversion

The simplest example - a sensor that converts temperature from °F to °C.

Legacy Syntax (DEPRECATED)

sensor:
- platform: template
sensors:
outside_temperature_celsius:
friendly_name: "Outside Temperature (°C)"
unit_of_measurement: "°C"
value_template: "{{ (states('sensor.outside_temperature') | float - 32) * 5/9 | round(1) }}"
template:
- sensor:
- name: "Outside Temperature (°C)"
unique_id: outside_temperature_celsius
unit_of_measurement: "°C"
state: "{{ (states('sensor.outside_temperature') | float - 32) * 5/9 | round(1) }}"
What Changed?
  • platform: templatemoved to template: section
  • sensors:removed (entities directly in list)
  • friendly_name:name:
  • value_template:state:
  • Added unique_id (optional but recommended)

Example 2: Binary Sensor - Is Window Open?

Binary sensor that detects whether a window is open based on a contact sensor.

Legacy Syntax (DEPRECATED)

binary_sensor:
- platform: template
sensors:
living_room_window:
friendly_name: "Living Room Window"
device_class: window
value_template: "{{ is_state('sensor.contact_living_room', 'open') }}"
template:
- binary_sensor:
- name: "Living Room Window"
unique_id: living_room_window
device_class: window
state: "{{ is_state('sensor.contact_living_room', 'open') }}"
What Changed?
  • binary_sensor with platform: templatetemplate: section with binary_sensor:
  • value_template:state:
  • Syntax is almost identical to regular sensors

Example 3: Sensor with Attributes - Weather

Sensor that displays weather information with additional attributes.

Legacy Syntax (DEPRECATED)

sensor:
- platform: template
sensors:
weather_summary:
friendly_name: "Weather - Summary"
value_template: "{{ states('weather.home') }}"
attribute_templates:
temperature: "{{ state_attr('weather.home', 'temperature') }}"
humidity: "{{ state_attr('weather.home', 'humidity') }}"
pressure: "{{ state_attr('weather.home', 'pressure') }}"
template:
- sensor:
- name: "Weather - Summary"
unique_id: weather_summary
state: "{{ states('weather.home') }}"
attributes:
temperature: "{{ state_attr('weather.home', 'temperature') }}"
humidity: "{{ state_attr('weather.home', 'humidity') }}"
pressure: "{{ state_attr('weather.home', 'pressure') }}"
What Changed?
  • attribute_templates:attributes:
  • Attributes are defined the same way, just a key name change

Example 4: Sensor with Dynamic Icon - Battery

Sensor that changes icon based on battery level.

Legacy Syntax (DEPRECATED)

sensor:
- platform: template
sensors:
sensor_battery:
friendly_name: "Sensor Battery"
unit_of_measurement: "%"
device_class: battery
value_template: "{{ states('sensor.xiaomi_sensor_battery') }}"
icon_template: >
{% set battery_level = states('sensor.xiaomi_sensor_battery') | float(0) %}
{% if battery_level > 90 %}
mdi:battery
{% elif battery_level > 70 %}
mdi:battery-70
{% elif battery_level > 50 %}
mdi:battery-50
{% elif battery_level > 30 %}
mdi:battery-30
{% elif battery_level > 10 %}
mdi:battery-10
{% else %}
mdi:battery-alert
{% endif %}
template:
- sensor:
- name: "Sensor Battery"
unique_id: sensor_battery
unit_of_measurement: "%"
device_class: battery
state: "{{ states('sensor.xiaomi_sensor_battery') }}"
icon: >
{% set battery_level = states('sensor.xiaomi_sensor_battery') | float(0) %}
{% if battery_level > 90 %}
mdi:battery
{% elif battery_level > 70 %}
mdi:battery-70
{% elif battery_level > 50 %}
mdi:battery-50
{% elif battery_level > 30 %}
mdi:battery-30
{% elif battery_level > 10 %}
mdi:battery-10
{% else %}
mdi:battery-alert
{% endif %}
What Changed?
  • icon_template:icon:
  • Template code remains the same, just the key name changes

Example 5: Trigger-based Sensor - Counter

Modern syntax enables creating trigger-based sensors that update only based on triggers (not every state change).

New Functionality (TRIGGER-BASED)

template:
- trigger:
- platform: state
entity_id: binary_sensor.motion_sensor
from: "off"
to: "on"
sensor:
- name: "Motion Count Today"
unique_id: motion_count_today
state: "{{ states('input_number.motion_counter') | int + 1 }}"
action:
- service: input_number.set_value
target:
entity_id: input_number.motion_counter
data:
value: "{{ states('input_number.motion_counter') | int + 1 }}"
New Features

Trigger-based sensors enable:

  • Precise control over updates
  • Triggering actions on update
  • Access to trigger data (trigger.to_state, trigger.from_state)
  • Better performance (fewer unnecessary updates)

Step-by-Step Migration Guide

1. Back Up Your Configuration

Before you start, always back up your configuration:

  • Settings → System → Backups (create backup)
  • Or manually copy configuration.yaml file

2. Find All Template Sensors

Search in files (typically configuration.yaml or packages/):

grep -r "platform: template" /config/

3. Perform Migration

For each sensor:

  1. Remove legacy definition from sensor: or binary_sensor: section
  2. Add new definition to template: section
  3. Change syntax according to table above
  4. Add unique_id (optional but recommended)
Important

DO NOT migrate statistics sensors (platform: statistics) - they use their own platform and remain in the sensor: section.

4. Check Configuration

In Home Assistant:

  • Developer Tools → YAML → Check Configuration
  • Verify there are no errors

5. Restart or Reload

You can use:

  • Full restart (Settings → System → Restart)
  • Or Template Entities Reload (Developer Tools → YAML → Template Entities)

6. Verify Functionality

After restart check:

  • Entities still exist with same entity ID
  • Values update correctly
  • Warning disappeared from logs

Common Issues and Solutions

❌ Entity Shows unknown State

Problem: After migration, entity shows unknown state.

Solution: Check that template returns valid value. Use states() function instead of states.sensor.xxx.state:

# ❌ WRONG
state: "{{ states.sensor.temperature.state }}"

# ✅ CORRECT
state: "{{ states('sensor.temperature') }}"

❌ Entity Doesn't Update

Problem: Entity stopped updating after migration.

Solution: Check that template contains all required entities. State-based sensors update automatically when referenced entities change.

❌ Duplicate template: Sections

Problem: You have multiple template: sections in configuration.yaml.

Solution: There can be only ONE template: section in file. Merge all definitions under one:

# ❌ WRONG
template:
- sensor:
- name: Sensor 1

template: # ← duplicate!
- sensor:
- name: Sensor 2

# ✅ CORRECT
template:
- sensor:
- name: Sensor 1
- sensor:
- name: Sensor 2

Complex Migration Example

Let's show migration of an entire package file with multiple sensors.

Before Migration (configuration.yaml)

sensor:
# SNMP sensor - KEEP UNCHANGED
- platform: snmp
host: 192.168.1.32
baseoid: 1.3.6.1.4.1.2021.10.1.3.1

# Template sensors - MIGRATE
- platform: template
sensors:
lights_on_count:
friendly_name: "Lights On Count"
unit_of_measurement: "lights"
value_template: "{{ states.light | selectattr('state', 'eq', 'on') | list | count }}"

average_temperature:
friendly_name: "Average Temperature"
unit_of_measurement: "°C"
device_class: temperature
value_template: >
{% set bedroom = states('sensor.bedroom_temp') | float %}
{% set kitchen = states('sensor.kitchen_temp') | float %}
{{ ((bedroom + kitchen) / 2) | round(1) }}

binary_sensor:
- platform: template
sensors:
anyone_home:
friendly_name: "Anyone Home"
device_class: occupancy
value_template: >
{{ is_state('person.john', 'home') or is_state('person.anna', 'home') }}

After Migration (configuration.yaml)

sensor:
# SNMP sensor - UNCHANGED
- platform: snmp
host: 192.168.1.32
baseoid: 1.3.6.1.4.1.2021.10.1.3.1

# Modern template syntax
template:
- sensor:
# Lights on count
- name: "Lights On Count"
unique_id: lights_on_count
unit_of_measurement: "lights"
state: "{{ states.light | selectattr('state', 'eq', 'on') | list | count }}"

# Average temperature
- name: "Average Temperature"
unique_id: average_temperature
unit_of_measurement: "°C"
device_class: temperature
state: >
{% set bedroom = states('sensor.bedroom_temp') | float %}
{% set kitchen = states('sensor.kitchen_temp') | float %}
{{ ((bedroom + kitchen) / 2) | round(1) }}

- binary_sensor:
# Anyone home
- name: "Anyone Home"
unique_id: anyone_home
device_class: occupancy
state: >
{{ is_state('person.john', 'home') or is_state('person.anna', 'home') }}
Important Notes
  • SNMP sensor remained in sensor: section - it's not a template
  • Template sensors were moved to new template: section
  • Entity IDs remain THE SAME (e.g., sensor.lights_on_count)
  • Automations and scripts will work WITHOUT CHANGES


Conclusion

Migrating to modern template syntax may seem complicated at first glance, but it's actually a simple change of key names and moving to a new section. Modern syntax is more readable, more powerful, and allows using new features like trigger-based sensors.

Important Terms:

  • Deadline: Version 2026.6 (June 2026)
  • 🔄 Backward Compatibility: Entity IDs remain the same
  • Impact: Minimal - no automation changes needed

If you're having trouble with migration, don't hesitate to ask in the comments below this article. Most issues are easily solvable and the community is happy to help!

Comments