Anuncio

Templates con Jinja2 en Home Assistant: Guía Definitiva de Sensores Virtuales

Si has seguido nuestra guía sobre organización en YAML, ya tienes tu sistema ordenado. Pero, ¿qué pasa cuando los datos que te dan tus dispositivos no son exactamente lo que necesitas?

Quizás tienes un sensor de temperatura que te da 23.56789ºC y tú solo quieres ver 23.5ºC. O tienes un sensor de puerta que dice on y tú quieres leer Abierta en tu móvil. O peor aún, quieres sumar el consumo de tres enchufes diferentes en un solo valor.

Para todo esto existe Jinja2. Es el traductor universal de Home Assistant, la herramienta que te permite «cocinar» los datos crudos para presentarlos exactamente como tú quieres.

💡 El mejor uso de Jinja2: Notificaciones de Voz
Jinja2 brilla cuando quieres que tu casa te hable de forma natural. En lugar de decir «Temperatura sala 20», puedes programar un Echo Dot (5.ª generación) para que diga: «Buenos días, la temperatura es agradable y tienes 2 ventanas abiertas» usando plantillas.

¿Qué es Jinja2 y por qué es esencial en la domótica?

Jinja2 es un motor de plantillas para el lenguaje Python. En palabras sencillas: es una forma de insertar código lógico dentro de archivos de texto.

En la domótica es esencial porque los dispositivos son tontos. Un sensor de humedad solo envía un número. Jinja2 es el cerebro que toma ese número y decide si es «Húmedo», «Seco» o «Confortable». Es el puente entre el dato bruto y la información útil para el humano.

Sin Jinja2, estarías limitado a ver lo que el fabricante del dispositivo quiere que veas. Con Jinja2, tú defines las reglas.

Conceptos básicos: La diferencia entre {{ … }} y {% … %}

Cuando veas código en foros o en la documentación, verás muchas llaves y porcentajes. No te asustes, solo hay dos reglas principales que debes memorizar:

  • Imprimir valor {{ ... }}:

    Se usa cuando quieres mostrar algo en la pantalla.

    Ejemplo: {{ 2 + 2 }} mostrará 4.

  • Lógica de control {% ... %}:

    Se usa para pensar (condicionales, bucles), pero no imprime nada por sí mismo.

    Ejemplo: {% if es_de_noche %} ... {% endif %}.

Tu primer Template: «Hola Mundo» con datos reales

Vamos a probar algo sencillo. Supongamos que quieres crear un saludo personalizado que cambie según quién está en casa. En lugar de escribir el nombre a mano, le pedimos a Home Assistant que busque el dato.

Un template básico se vería así:

Hola, el estado del sol es: {{ states('sun.sun') }}

Resultado: «Hola, el estado del sol es: above_horizon».
Acabas de mezclar texto estático («Hola…») con un dato dinámico extraído en tiempo real de tu base de datos.

Herramientas imprescindibles: El Editor de Plantillas (Developer Tools)

Regla de Oro: NUNCA escribas una plantilla directamente en tu archivo YAML sin probarla antes.

Home Assistant tiene un «banco de pruebas» maravilloso. Ve a la barra lateral izquierda:

  1. Clic en Herramientas para desarrolladores (martillo).
  2. Clic en la pestaña Plantilla (Template).

Aquí verás un editor de texto a la izquierda y el resultado en tiempo real a la derecha. Es tu zona segura. Puedes escribir, borrar y equivocarte las veces que quieras sin romper tu configuración. Solo cuando veas que el resultado a la derecha es correcto, copias el código y lo llevas a tu archivo YAML.

📚 Documentación Oficial

Aunque esta guía te enseñará lo esencial, ten siempre a mano la documentación oficial de Templating. Es la biblia donde encontrarás todos los filtros y funciones disponibles.

Accediendo a los Datos: Entidades, Estados y Atributos

Para crear lógica, necesitas datos. En Home Assistant, cada dispositivo es una «Entidad» (ej: light.salon), y esa entidad tiene dos partes fundamentales de información:

  1. El Estado (State): La información principal (ej: «on», «off», «21.5»).
  2. Los Atributos (Attributes): Datos secundarios ocultos (ej: nivel de batería, brillo, color, modo de ventilador).

Jinja2 es tu pico y pala para extraer ambos.

Cómo obtener el estado de un sensor (states())

La función más usada es states(). Simplemente pones la ID de la entidad entre paréntesis y comillas, y te devuelve su estado actual.

El salón está: {{ states('light.luz_techo') }}
La temperatura es: {{ states('sensor.temperatura_salon') }}

⚠️ Trampa para principiantes: Todo es Texto

Recuerda esto: Home Assistant devuelve todos los estados como TEXTO (Strings), incluso si parecen números.

Si intentas hacer {{ states('sensor.temp') + 1 }}, fallará.

Tienes que convertirlo a número primero: {{ states('sensor.temp') | float + 1 }}. Veremos los filtros matemáticos más adelante.

Extrayendo atributos ocultos (state_attr())

A veces el dato interesante no es el estado. Imagina una estación meteorológica.

💡 El Rey de los Atributos: Dispositivos como la Estación Meteorológica Netatmo son perfectos para practicar. Su entidad principal muestra la temperatura, pero oculta datos valiosos como el nivel de CO2, la presión atmosférica o el ruido en sus atributos. Sin Jinja2, te pierdes la mitad de la información por la que has pagado.

Para leer esos datos «escondidos», usamos state_attr(). Necesitas dos argumentos: la entidad y el nombre del atributo.

Nivel de Batería: {{ state_attr('sensor.movimiento_pasillo', 'battery_level') }} %
Brillo de la luz: {{ state_attr('light.salon', 'brightness') }}

Para saber qué atributos tiene un dispositivo, ve a Herramientas para desarrolladores > Estados y mira la columna de la derecha.

Diferencias clave entre el objeto Estado y el valor del Estado

Verás en foros antiguos código como este: {{ states.sensor.temperatura.state }}.

Esto accede directamente al Objeto en la memoria de Python. Aunque funciona, es una MALA PRÁCTICA.

  • Método Objeto (Malo): states.sensor.x.state. Si la entidad no está lista al arrancar, genera un error y bloquea la plantilla.
  • Método Función (Bueno): states('sensor.x'). Si la entidad no existe, devuelve suavemente unknown sin romper nada. Usa siempre este método.

Manejo de errores: ¿Qué pasa si la entidad no existe?

Cuando reinicias Home Assistant, hay unos segundos donde los sensores Zigbee o WiFi aún no han conectado. En ese momento, su estado es unavailable o unknown.

Si tienes una plantilla matemática, esto causará errores en los logs. Para evitarlo, debemos proveer un valor por defecto (default value) usando filtros.

# ❌ PELIGROSO: Si el sensor no va, esto explota
{{ states('sensor.consumo') | float }}

# ✅ SEGURO: Si el sensor no va, usa un 0
{{ states('sensor.consumo') | float(0) }}

Acostúmbrate a poner siempre un valor por defecto entre paréntesis. Es el cinturón de seguridad de tus sensores virtuales.

Manipulación de Datos: Filtros y Transformaciones

En Jinja2, el símbolo más poderoso es la barra vertical o «tubería» (|). En inglés se llama Pipe.

Imagina que el dato entra por la izquierda de la tubería, pasa por un filtro que lo modifica, y sale por la derecha. Puedes encadenar tantas tuberías como quieras.

Filtros matemáticos básicos y redondeo

Como mencionamos antes, Home Assistant ve casi todo como texto. Si intentas sumar «20» + «20», obtendrás «2020», no 40. Primero debemos convertir.

💡 Práctica Real: ¿Cuánto consume tu oficina? Si tienes varios dispositivos conectados a enchufes inteligentes como los Tapo P110 con Monitor de Energía, puedes usar Jinja2 para sumar sus consumos en tiempo real y crear un «Sensor Virtual de Oficina».

Conversión de tipos: int, float y valores por defecto

Usa int para números enteros (sin decimales) y float para decimales.

# Convierte a entero (redondea hacia abajo)
{{ "25.8" | int(0) }}  -> Resultado: 25

# Convierte a decimal
{{ "25.8" | float(0) }} -> Resultado: 25.8

Nota: El (0) entre paréntesis es el valor de seguridad. Si el sensor falla, usará un 0 en lugar de dar error.

Operaciones aritméticas dentro de las llaves

Una vez convertidos, puedes usar matemáticas normales (+, -, *, /).

# Sumar dos sensores y redondear a 2 decimales
{{ (states('sensor.consumo_pc') | float(0) + states('sensor.consumo_monitor') | float(0)) | round(2) }}

Manipulación de cadenas de texto (Strings)

A veces el dato es correcto, pero feo. Jinja2 te permite maquillar el texto para tus dashboards.

Reemplazar, cortar y formatear texto

  • Replace: Cambia partes del texto.

    {{ "alarma_armada_casa" | replace("_", " ") | title }}

    Resultado: «Alarma Armada Casa»

  • Truncate: Corta textos largos (útil para noticias RSS).

    {{ states('sensor.noticias') | truncate(20) }}

Uso de regex para extracciones complejas (Nivel Experto)

Si necesitas sacar un dato muy específico de un texto largo (ej: un código de error dentro de un log), usa regex_findall_index.

Ejemplo: Extraer solo los números de «Error Code: 404 Not Found».

{{ "Error Code: 404 Not Found" | regex_findall_index("\d+") }} -> Resultado: 404

Para probar tus patrones, usa Regex101.

Trabajando con Listas y Diccionarios

Aquí es donde Jinja2 se vuelve «Dios». Puedes procesar grupos enteros de entidades a la vez.

Filtros map, select y reject

Imagina que quieres saber qué ventanas están abiertas, no solo cuántas.

  1. expand('group.todas_ventanas'): Convierte el grupo en una lista de entidades.
  2. selectattr('state', 'eq', 'on'): Se queda solo con las que están abiertas (‘on’).
  3. map(attribute='name'): De esas entidades, extrae solo su nombre.
  4. list: Lo convierte en una lista limpia.
{{ expand('group.todas_ventanas') | selectattr('state', 'eq', 'on') | map(attribute='name') | list }}

Resultado: ['Ventana Cocina', 'Ventana Baño'].

Cómo iterar datos con bucles for

Si quieres imprimir esa lista de forma bonita (por ejemplo, para que Alexa la lea), usas un bucle.

Las ventanas abiertas son:
{% for ventana in expand('group.todas_ventanas') | selectattr('state','eq','on') %}
  - {{ ventana.name }}
{% endfor %}
Uso de loop.index y loop.last

Para hablar con naturalidad, no queremos una coma al final de la frase. Usamos loop.last para detectar el último elemento.

Atención, tienes abiertas: 
{% for ventana in expand('group.todas_ventanas') | selectattr('state','eq','on') %}
  {{ ventana.name }}{% if not loop.last %}, {% else %}.{% endif %}
{% endfor %}

Resultado: «Atención, tienes abiertas: Ventana Cocina, Ventana Baño.» (Fíjate en el punto final).

Lógica de Control: Haciendo tus sensores inteligentes

Hasta ahora hemos transformado datos, pero no hemos tomado decisiones. La verdadera potencia de Jinja2 aparece cuando le enseñas a Home Assistant a pensar: «Si pasa A, haz B. Si no, haz C».

Recuerda que para la lógica no usamos las dobles llaves {{ }}, sino la sintaxis de porcentaje: {% ... %}.

Estructuras condicionales if, elif y else

Es la base de cualquier programación. Vamos a crear un texto dinámico para el nivel de batería de un sensor.

  • if (Si…): La primera condición.
  • elif (Si no, pero si…): Condiciones intermedias (puedes poner tantas como quieras).
  • else (Si no…): El cajón de sastre final. Si nada de lo anterior se cumple, se ejecuta esto.
  • endif: Obligatorio para decirle a Jinja dónde termina la lógica.
{% set bateria = states('sensor.movimiento_bateria') | int(0) %}

Estado de la batería:
{% if bateria > 80 %}
  🟢 Excelente ({{ bateria }}%)
{% elif bateria > 20 %}
  🟡 Normal ({{ bateria }}%)
{% else %}
  🔴 ¡Cambiar Pila! ({{ bateria }}%)
{% endif %}

Operadores lógicos: and, or, not y paréntesis

La vida real rara vez depende de una sola cosa. Normalmente quieres que ocurra algo si se cumplen varias condiciones a la vez.

💡 Escenario de Seguridad: Imagina que tienes un Aqara Door & Window Sensor P2 (Matter). Quieres un sensor virtual que te diga «ALERTA DE INTRUSO» solo si la puerta está abierta Y (AND) la alarma está armada, pero que ignore la puerta si estás en modo «Noche».

Para combinar condiciones, usa estos operadores:

  • and: Ambas deben ser verdad.
  • or: Basta con que una sea verdad.
  • not: Invierte el valor (True se vuelve False).
  • ( ): Paréntesis. Vitales para agrupar y definir el orden, igual que en matemáticas.
{% if (is_state('binary_sensor.puerta', 'on') and is_state('alarm_control_panel.casa', 'armed_away')) %}
  🚨 ¡INTRUSO!
{% else %}
  Todo tranquilo
{% endif %}

El problema del «Scope»: Uso de namespace para variables globales

Aquí es donde el 90% de los usuarios se rinden. Presta atención.

En Jinja2, las variables tienen un «alcance» (scope). Si defines una variable dentro de un bucle for, esa variable muere cuando termina la vuelta del bucle. No puedes usarla para contar cosas hacia afuera.

El error común (Esto NO funciona):

{% set contador = 0 %}
{% for luz in states.light %}
  {% if luz.state == 'on' %}
    {% set contador = contador + 1 %} {# <--- Este cambio se pierde al cerrar el if #}
  {% endif %}
{% endfor %}
Total encendidas: {{ contador }}  {# <--- Resultado: 0 (¡Frustración!) #}

La solución: Usar namespace()
Un namespace es como una mochila que puedes llevar dentro y fuera del bucle. Los datos guardados ahí persisten.

{% set ns = namespace(contador=0) %} {# Creamos la mochila 'ns' #}

{% for luz in states.light %}
  {% if luz.state == 'on' %}
    {% set ns.contador = ns.contador + 1 %} {# Guardamos en la mochila #}
  {% endif %}
{% endfor %}

Total encendidas: {{ ns.contador }} {# <--- Resultado: 5 (¡Funciona!) #}

🔗 Relacionado

Este concepto de persistencia de variables es similar al uso de «Flow Context» que explicamos en nuestra guía de Lógica Compleja en Node-RED, pero aplicado a código puro.

Guía Práctica: Creando Sensores Virtuales (Template Sensors)

Ya sabes escribir Jinja2 en el editor de pruebas. Ahora vamos a hacer esos cambios permanentes. Vamos a crear entidades nuevas que aparecerán en tu sistema como si fueran dispositivos físicos.

La estructura moderna en YAML (template:)

⚠️ Aviso Importante: Si buscas tutoriales antiguos, verás código que empieza por sensor: - platform: template. Ese formato es «Legacy».

La forma moderna y recomendada por Home Assistant es usar la integración de nivel superior template:. Es más potente y permite nuevas funciones como los «Trigger-based sensors».

Caso Práctico 1: Sensor Binario de Presencia Combinada

Imagina que tienes un salón grande con dos sensores de movimiento (uno en la entrada y otro en el sofá). Quieres saber si la sala está ocupada si cualquiera de los dos detecta algo.

💡 Estrategia Económica: En lugar de comprar un caro sensor de presencia milimétrica (Aqara FP2), puedes lograr un resultado muy similar combinando dos sensores PIR baratos (Sonoff SNZB-03) en esquinas opuestas y usando este Template Sensor para unificarlos.

Crea esto en tu archivo YAML (o en un Package):

template:
  - binary_sensor:
      - name: "Presencia Salón Unificada"
        unique_id: presencia_salon_total_01
        state: >
          {{ is_state('binary_sensor.movimiento_entrada', 'on')
             or is_state('binary_sensor.movimiento_sofa', 'on') }}
        device_class: occupancy
        delay_off: "00:02:00"

Configuración de device_class y delay_off

  • device_class: occupancy: Esto le dice a Home Assistant que no muestre «Encendido/Apagado», sino «Ocupado/Libre» y cambie el icono automáticamente a una persona.
  • delay_off: ¡Magia pura! Esta línea mantiene el sensor en «Ocupado» durante 2 minutos extra después de que los sensores reales hayan dejado de detectar movimiento. Es perfecto para evitar que la luz se apague mientras lees quieto en el sofá.

Caso Práctico 2: Sensor de cálculo de costes de energía

Tienes un enchufe que mide Watts, pero quieres ver Euros. Vamos a usar matemáticas.

template:
  - sensor:
      - name: "Coste Lavadora Actual"
        unique_id: coste_lavadora_eur
        state: >
          {% set potencia = states('sensor.lavadora_power') | float(0) %}
          {% set precio_kwh = states('sensor.precio_luz_actual') | float(0) %}
          {{ (potencia / 1000 * precio_kwh) | round(3) }}
        unit_of_measurement: "€/h"
        state_class: measurement

Uso de unit_of_measurement y state_class

Estas dos líneas son obligatorias si quieres gráficas bonitas.

  • unit_of_measurement: Define la unidad (EUR, W, ºC). Sin esto, el historial será una barra de colores en lugar de una línea gráfica.
  • state_class: Le dice a Home Assistant cómo tratar los datos.

    measurement: Para valores que oscilan (temperatura, potencia).

    total_increasing: Para contadores que siempre suben (energía total kWh). Vital para el Panel de Energía.

Trigger-based Sensors: Actualización bajo demanda

Los sensores normales se actualizan SIEMPRE que cambian sus fuentes. A veces eso es demasiado. Los Trigger-based Sensors funcionan como una automatización: solo se actualizan cuando ocurre un evento específico.

template:
  - trigger:
      - platform: time
        at: "00:00:00"
    sensor:
      - name: "Temperatura al Medianoche"
        state: "{{ states('sensor.temperatura_exterior') }}"
        unit_of_measurement: "°C"

Este sensor tomará una «foto» de la temperatura a medianoche y mantendrá ese valor estático durante 24 horas, ignorando los cambios posteriores.

Ventajas de rendimiento frente a sensores normales

Al no recalcularse cada segundo, ahorran CPU. Son ideales para cálculos pesados o para capturar datos puntuales (ej: «¿A qué precio estaba la luz cuando puse la lavadora?»).

Persistencia de datos tras reinicios

Esta es la mejor característica. A diferencia de los sensores template normales que se reinician o marcan unknown al reiniciar el servidor, los Trigger-based Sensors recuerdan su último valor tras un reinicio. Son perfectos para guardar contadores o estados que no quieres perder.

Dominando el Tiempo: Fechas y Horas en Jinja2

Si alguna vez has intentado restar dos horas en Home Assistant y has recibido un error gigante en rojo, bienvenido al club. El manejo del tiempo es delicado porque no puedes restar «Peras» (Texto) con «Manzanas» (Objetos de tiempo).

Para dominar esto, necesitas entender los objetos temporales nativos de Python que Jinja2 nos permite usar.

El objeto now() y utcnow()

Estas son las funciones base. No necesitan argumentos.

  • now(): Devuelve la fecha y hora actual en tu Zona Horaria Local. Es lo que usarás el 99% de las veces para mostrar datos en pantalla.
  • utcnow(): Devuelve la hora en formato UTC (Tiempo Universal Coordinado, +00:00). Es útil para cálculos internos del sistema o comparar con sensores que vienen en bruto desde la nube.
Hora local: {{ now() }} 
# Salida: 2023-10-27 18:30:05.123456+02:00

Hora UTC: {{ utcnow() }}
# Salida: 2023-10-27 16:30:05.123456+00:00

Solo la hora: {{ now().hour }}:{{ now().minute }}

Conversión de Timestamps y Strings

El problema llega cuando tu sensor no te da un objeto bonito como now(), sino un texto raro como "Fri, 27 Oct 2023".

Uso de as_timestamp y strptime

Tenemos dos herramientas para normalizar datos:

  • as_timestamp(valor): Convierte una fecha en un número simple (segundos desde 1970). Es perfecto para hacer restas matemáticas.
  • strptime(texto, formato): «Parsear Tiempo». Convierte un texto extraño en un objeto de fecha real que Home Assistant entienda.
# Convertir fecha a segundos (para restar)
{{ as_timestamp(now()) }} -> 1698424205.5

# Leer una fecha rara de un sensor
{% set fecha_rara = "27/10/2023 18:30" %}
{{ strptime(fecha_rara, "%d/%m/%Y %H:%M") }}

Cálculos de diferencias de tiempo (Deltas)

Para saber cuánto tiempo ha pasado entre dos eventos, simplemente restamos objetos de fecha. El resultado es un objeto especial llamado timedelta.

# ¿Cuántos días faltan para Navidad?
{{ (strptime("2023-12-25", "%Y-%m-%d").date() - now().date()).days }} días.
Crear un sensor de «Tiempo restante para…»

Vamos a aplicar todo esto para crear un sensor que nos diga cuánto falta para que termine la lavadora, mostrando un formato legible para humanos.

template:
  - sensor:
      - name: "Tiempo Restante Lavadora"
        state: >
          {% set fin = states('sensor.lavadora_hora_fin') | as_datetime %}
          {% set falta = fin - now() %}
          {% set horas = (falta.seconds // 3600) %}
          {% set minutos = (falta.seconds // 60) % 60 %}
          
          {% if falta.days < 0 %}
            Finalizado
          {% else %}
            {{ horas }}h {{ minutos }}m
          {% endif %}

Este código calcula la diferencia, extrae horas y minutos matemáticamente, y maneja el caso de que el tiempo ya haya pasado.

Técnicas Avanzadas y Buenas Prácticas (Para Expertos)

Cuando empiezas a llenar tu configuración de plantillas, corres un riesgo: matar el rendimiento de tu servidor. Jinja2 es rápido, pero si le pides que recalcule mil cosas cada segundo, tu Home Assistant se volverá lento.

Optimización del rendimiento y el «Render Loop»

Debes entender cómo funciona el motor. Home Assistant analiza tu plantilla para ver qué entidades usas. Si escribes states('sensor.temperatura'), el sistema se «suscribe» a ese sensor. Cada vez que la temperatura cambia, la plantilla se vuelve a calcular (renderizar).

El error mortal: Iterar sobre TODO
Si escribes {% for s in states.sensor %}, estás obligando a Home Assistant a escuchar los cambios de TODOS los sensores de tu casa. Si tienes 200 sensores, tu plantilla se recalculará cientos de veces por minuto, disparando el uso de CPU.

La solución: Acota siempre el alcance. Usa grupos o itera sobre áreas específicas, nunca sobre dominios enteros (states.*) a menos que sea estrictamente necesario y sepas lo que haces.

Reutilización de código con Macros de Jinja

¿Te encuentras copiando y pegando la misma lógica de colores para baterías en 20 sensores distintos? Eso viola el principio DRY. Las macros son como «funciones» que escribes una vez y usas donde quieras.

Definición e importación de macros personalizadas

Desde las versiones recientes de Home Assistant, puedes crear una carpeta llamada custom_templates en tu directorio de configuración.

Paso 1: Crear la Macro
Crea el archivo /config/custom_templates/herramientas.jinja:

{% macro formato_bateria(nivel) %}
  {% if nivel | int > 80 %} 🟢
  {% elif nivel | int > 30 %} 🟡
  {% else %} 🔴
  {% endif %}
  {{ nivel }}%
{% endmacro %}

Paso 2: Usarla en tus sensores
Ahora, en cualquier parte de tu configuración YAML, puedes importar y usar esa función:

{% from 'herramientas.jinja' import formato_bateria %}

El sensor del pasillo está: {{ formato_bateria(states('sensor.pasillo_bat')) }}

Si mañana quieres cambiar el icono amarillo por uno naranja, solo editas el archivo .jinja y se actualiza en toda la casa.

Manipulación de JSON complejo (API Responses)

Muchos servicios web (APIs) y dispositivos MQTT envían la información empaquetada en formato JSON. A veces es un objeto gigante con datos anidados.

Navegación segura en JSON anidado (from_json)

Imagina que un sensor REST te devuelve esto en su atributo body:

{"clima": {"actual": {"temp": 20, "humedad": 50}, "alerta": false}}

Para leer la temperatura, primero debemos convertir ese texto (String) en un objeto real (Diccionario) usando el filtro from_json.

{% set datos = states('sensor.api_clima_raw') | from_json %}
La temperatura es: {{ datos.clima.actual.temp }} ºC

🛡️ Navegación Defensiva

¿Qué pasa si la API falla y no envía el campo «actual»? La plantilla daría error. Para evitarlo, usa corchetes para acceder a las claves si no estás seguro de que existan:

{{ datos['clima']['actual']['temp'] }}

Solución de problemas comunes

Incluso los expertos cometen errores de sintaxis. Si tu plantilla no funciona o tu sensor desaparece, suele ser por una de estas dos razones.

Errores frecuentes al renderizar

Si ves errores en los logs del tipo TemplateError o TypeError, casi siempre es un problema de tipos de datos.

  • El error: Intentar hacer matemáticas con texto.

    {{ states('sensor.temp') + 1 }} ❌ Falla.

  • La solución: Convertir siempre a número.

    {{ states('sensor.temp') | float(0) + 1 }} ✅ Funciona.

Otro clásico es olvidar cerrar las llaves. {{ states('sensor.x') sin las dos llaves de cierre }} hará que toda tu configuración YAML sea inválida.

Por qué tu sensor muestra «Unavailable» o «Unknown»

Has creado tu sensor perfecto, reinicias Home Assistant y… pone «Unavailable». ¿Por qué?

La causa: Orden de arranque. Tu sensor Template intenta calcular su valor antes de que el sensor físico (Zigbee/WiFi) se haya conectado y reportado datos.

La solución: Valores por defecto (Defaults).

Si usas filtros como | float(0), tu sensor mostrará «0» en lugar de «Unavailable» mientras arranca.

Si quieres ser más profesional, configura la opción availability en tu sensor template para definir explícitamente cuándo debe funcionar y cuándo debe mostrarse como no disponible.

💡 Visualiza tus logros: Ahora que tienes sensores virtuales con datos perfectos, necesitas una pantalla a la altura. El Echo Show 8 (3.ª gen) es ideal para crear un dashboard táctil en la cocina y ver de un vistazo esos datos complejos que acabas de simplificar con Jinja.


Preguntas Frecuentes (FAQ)

¿Usar muchos Templates ralentiza Home Assistant?

Si están bien hechos, no. Home Assistant es muy eficiente. Sin embargo, si usas bucles que iteran sobre states.sensor (todos los sensores de la casa) o usas now() sin control en sensores normales (no trigger-based), puedes causar picos de CPU. Sé específico al elegir tus entidades origen.

¿Por qué mi plantilla con now() no se actualiza cada segundo?

Por diseño, Home Assistant limita las actualizaciones de tiempo a una vez por minuto para no saturar el sistema. Si necesitas precisión de segundos (para un cronómetro), debes usar un sensor trigger-based o hacerlo en el Frontend (tarjeta de Lovelace), no en el Backend (Jinja).

¿Puedo usar Python normal dentro de Jinja2?

No. Jinja2 se parece a Python, pero es limitado por seguridad. No puedes importar librerías externas ni acceder al sistema de archivos. Solo puedes usar las funciones y filtros que Home Assistant expone.

¿Dónde es mejor poner estas plantillas?

Recomendamos encarecidamente usar YAML Packages. Crea un archivo como packages/sensores_virtuales.yaml y agrupa allí toda tu lógica para mantener limpio tu archivo de configuración principal.

¿Te ha sido útil? ¡Compártelo con otros!

Únete a la Comunidad

Síguenos en nuestras redes para ver tutoriales en vídeo, ideas de decoración y trucos rápidos para tu hogar inteligente.