• Autor de la entrada:
  • Tiempo de lectura:9 minutos de lectura

Descripción de la integración de Home-Ambient en Home Assistant mediante el framework ESPHome. Integración de varias configuraciones como climatizador, sensores ambientales, actuadores y displays de tinta electrónica.

Introducción

ESPHome es un framework para crear firmwares personalizados que se integran muy fácilmente con Home Assistant. El hardware soportado es el basado principalmente en ESP8266 y ESP32, si bien también soporta RP2040 y ha comenzado un desarrollo para el nRF52840.

A diferencia de la programación en C/C++, en ESPHome el comportamiento se define mediante archivos de configuración YAML (texto plano legible).

Integración termostato

El termostato es el componente principal de Home-Ambient y su razón de ser. ESPHome dispone de este componente para usar de una forma muy directa y sencilla, simplemente se debe definir un sensor que mida el parámetro a controlar y un actuador que gobierne el elemento calefactor.

Sensores y actuadores en ESPHome

La integración de sensores y actuadores con ESPHome puede ser cualquiera de las descritas a continuación. Es posible utilizar cualquier tipo de sensor, incluso fusionar varios promediando o añadiendo lógicas diversas.

BME680. Temperatura, humedad, presión y calidad del aire

BME680 en Home Ambient
BME680 en Home Ambient

Para más información sobre este sensor consultar la documentación oficial en ‘ESPHome: BME 68X via BSEC2’.

El sensor BME680 depende de un canal I2C como interfaz de comunicación. Se especifican los pines físicos, la velocidad y la activación de un escaneo automático al iniciar. Este escaneo es muy útil para diagnóstico y depuración. La asignación de un identificador sirve para referenciar sin lugar a dudas este bus.

A continuación, se establece la configuración específica del sensor ambiental, sin incluir nada que merezca especial atención.

Finalmente, se describen las magnitudes ambientales que serán publicadas, ajustando las cifras significativas. El filtro ‘delta’ ayuda a reducir el tráfico de datos al obviar cambios de estado inferiores al indicado.

‘text_sensor:’ podría excluirse sin problema, aunque aporta información que podría resultar vistosa en algunos dashboards de Home Assistant.

# BME68X I2C bus
i2c:
  sda: GPIO6
  scl: GPIO7
  frequency: 400kHz
  scan: true
  id: i2c_a

# BME68X Device
bme68x_bsec2_i2c:
  i2c_id: i2c_a
  address: 0x77
  model: bme680
  operating_age: 28d
  sample_rate: ULP
  supply_voltage: 3.3V
  state_save_interval: 6h

sensor:
  # BME68X Sensor reading
  # Temperature, humidity, pressure air quality sensor
  - platform: bme68x_bsec2
    temperature:
      id: temperature_sensor
      name: "Temperature"
      accuracy_decimals: 1
      filters: 
        - delta: 0.2
    pressure:
      id: pressure_sensor
      name: "Pressure"
      unit_of_measurement: mbar
      accuracy_decimals: 0
      filters: 
        - delta: 1
    humidity:
      id: humidity_sensor
      name: "Humidity"
      accuracy_decimals: 0
      filters: 
        - delta: 1
    co2_equivalent:
      name: "CO2 Equivalent"
      accuracy_decimals: 0
    breath_voc_equivalent:
      name: "Breath VOC Equivalent"

text_sensor:
    - platform: bme68x_bsec2
      iaq_accuracy:
        name: "IAQ Accuracy"

    - platform: template
      name: "IAQ Classification"
      lambda: |-
        if ( int(id(iaq).state) <= 50) {
          return {"Excellent"};
        }
        else if (int(id(iaq).state) >= 51 && int(id(iaq).state) <= 100) {
          return {"Good"};
        }
         else if (int(id(iaq).state) >= 101 && int(id(iaq).state) <= 150) {
            return {"Lightly polluted"};
        }
        else if (int(id(iaq).state) >= 151 && int(id(iaq).state) <= 200) {
            return {"Moderately polluted"};
        }
        else if (int(id(iaq).state) >= 201 && int(id(iaq).state) <= 250) {
            return {"Heavily polluted"};
        }
        else if (int(id(iaq).state) >= 251 && int(id(iaq).state) <= 350) {
            return {"Severely polluted"};
        }
        else if (int(id(iaq).state) >= 351) {
            return {"Extremely polluted"};
        }
        else {
            return {"error"};
        }

Sensor de temperatura analógico

Aunque un sensor analógico no es una opción de precisión, resulta muy económico y podría servir en multitud de situaciones.

LMT85 en Home Ambient
LMT85 en Home Ambient
sensor:
  # Analog temperature monitor
  - platform: adc
    id: temperature_sensor
    pin: GPIO0
    name: "Temperature"
    attenuation: 12db
    unit_of_measurement: "°C"
    accuracy_decimals: 1
    update_interval: 10s
    filters:
      - sliding_window_moving_average:
          window_size: 12
          send_every: 12
      - multiply: 1000
      - lambda: return (1575 - x) / (8.1f);
      - delta: 0.2

Es prácticamente obligatorio filtrar una lectura analógica de un ESP32-C3. El filtro utilizado es una media móvil de dos minutos, con muestras cada 10 segundos. Solo se publican variaciones de temperatura superiores a 0,2°C.

Las operaciones matemáticas sirven para convertir la lectura en milivoltios del ADC a temperatura en grados centígrados para el sensor LMT85.

Las o

Lectura analógica en ESP32-C3, filtrada y comparación con BME680
Arriba abajo: 1.Lectura analógica sin filtrar. 2. Lectura analógica filtrada. 3.Lectura de el BME680.

Leer sensores/datos de Home Assistant

En ocasiones puede ser necesario obtener el valor de un sensor o estado que se esté ejecutando en el propio Home Assistant, las posibilidades son infinitas. En el siguiente ejemplo se obtiene la temperatura de un sensor situado en la calle.

sensor:
  # Street parameters
  - platform: homeassistant
    id: street_temp_id
    entity_id: sensor.street_temperature

Actuador y contador energético

Un añadido muy interesante al actuador del calefactor es el conteo de la energía consumida. Es totalmente opcional, pero resulta muy interesante para quien desea obtener datos y estadísticas.

Integración "Energía" en Home Ambient

Obviamente la medida no es 100% real, pero el sistema no necesitará un medidor dedicado, estimando el consumo energético basándose en la potencia conocida del calentador y el tiempo que permanece encendido.

sensor:
  # Virtual power sensor
  - platform: template
    name: "Power"
    id: thermostat_power
    state_class: measurement
    device_class: power
    unit_of_measurement: "W"
    accuracy_decimals: 0

  # Virtual energy sensor
  - platform: integration
    name: "Energy"
    sensor: thermostat_power
    time_unit: h
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: "kWh"
    accuracy_decimals: 3
    integration_method: left
    filters:
      - multiply: 0.001

# Heating relay
switch:
  - platform: gpio
    id: heater_switch
    pin: GPIO4
    name: "Heater"

    on_turn_on:
      - sensor.template.publish:
          id: thermostat_power
          # Heating power
          state: 2300

    on_turn_off:
      - sensor.template.publish:
          id: thermostat_power
          state: 0

Obligatoriamente solo es necesario declarar un switch para que el termostato funcione, por lo que todo lo demás es totalmente opcional.

Se crea un sensor de potencia basado en template que no mide un valor físico real, sino un valor asignado internamente. Se configura como una magnitud de potencia y con clase measurement, lo que permite que Home Assistant lo interprete correctamente dentro de la aplicación de energía.

Un segundo sensor calcula la energía consumida. Al integrar la potencia instantánea se tiene la energía total expresada en kilovatios hora. Se aplica un factor de conversión para adaptar la escala de unidades y se asigna la clase energy.

Cuando el calentador se enciende, se publica un valor fijo de potencia que representa el consumo nominal del equipo.

Termostato

climate:
  - platform: thermostat
    name: "Thermostat"
    id: ha_thermostat
    sensor: temperature_sensor
    visual:
      min_temperature: 10
      max_temperature: 28
      temperature_step: 0.2

    min_heating_off_time: 30s
    min_heating_run_time: 5s
    min_idle_time: 30s
    heat_deadband: 0.3
    heat_overrun: 0.5
    
    heat_action:
      - switch.turn_on: heater_switch
      - light.turn_on:
                  id: rgb_led
                  red: 1.0
                  green: 0.0
                  blue: 0.0
                  brightness: 0.5
    idle_action:
      - switch.turn_off: heater_switch
      - light.turn_off: rgb_led

    default_preset: Home
    preset:
      - name: Home
        default_target_temperature_low: 12 °C

Este bloque configura un termostato digital que utiliza la temperatura medida como referencia para controlar automáticamente el sistema de calefacción.

Se define un tiempo mínimo entre encendidos, así como un tiempo mínimo de funcionamiento una vez encendida. También se fija un periodo mínimo en estado inactivo y un margen de histéresis alrededor de la temperatura objetivo.

Como depuración, se enciende el RGB en rojo para mostrar que la calefacción está funcionando.

Finalmente, default_preset define una temperatura inicial baja cuando el sistema arranca o tras reinicios.

Una vez implementado el termostato es posible obtener un control como el siguiente:

Integración de Termostato en Home Assistant
Integración de Termostato en Home Assistant

Programador de temperaturas

Programar las temperaturas de un termostato es la principal característica de un termostato inteligente. En Home Assistant sería posible realizar esto mediante automatizaciones, sin embargo, gestionar esto sería tedioso.

Una opción flexible y fiable es el programador desarrollado por Niels Faber.

Programador de nielsfaber para Home Assistant
Tarjerta programador de nielsfaber para Home Assistant

Instalar este programador en Home Assistant no es complicado, pero tampoco fácil. Como es un proyecto vivo, lo mejor es acudir a la fuente para encontrar el manual de instalación y usuario. Consta de dos partes que deben instalarse en orden:

  1. Componente programador (scheduler-component).
  2. Tarjeta programador (card-scheduler).

Display e-Paper y Waveshare

Para este proyecto se ha utilizado una pantalla de tinta electrónica de 4,2″ con una resolución de 400×300 pixeles. La elección se realizó fundamentalmente por ser el mayor tamaño disponible para el formato del termostato, el precio también ayudó a la decisión al ser un display económico.

Integración de display e-ink en Home Ambient
Muestra display e-ink en Home Ambient

Configuración e impresión de una imagen

spi:
  id: spi_a
  clk_pin: GPIO2
  mosi_pin: GPIO5

image:
  - file: "P_FC.bmp"
    type: binary
    id: floor_plan
    invert_alpha: true

display:
  - platform: waveshare_epaper
    spi_id: spi_a
    model: gdey042t81
    cs_pin: GPIO3
    busy_pin: GPIO18
    dc_pin: GPIO10
    reset_pin: GPIO19
    reset_duration: 2ms
    update_interval: 60s
    full_update_every: 1

    lambda: |-
      auto color_back = COLOR_OFF;
      auto color_print = COLOR_ON;
      it.fill(color_back);
      it.image(0, 0, id(floor_plan));

La interfaz con el display se realiza a través de un canal SPI.

El siguiente paso es la propia implementación del display con la directiva display: seguida de la configuración hardware básica. Importante a tener en cuenta es el modelo de driver declarado. Solo ha funcionado el ‘gdey042t81’, y no con ninguno de la familia ‘4.20in’.

Finalmente se muestra como ejemplo la visualización de una imagen, que en este caso es el plano de una planta de un piso, sobre la que se irá mostrando información con las herramientas que proporciona el componente display que se irán mostrando a continuación.

Invertir color en display e-Ink
Invertir color en display e-Ink

En el ejemplo anterior las declaraciones de las variables color_back y color_print son opcionales, pero recomendables al dar un control total en el momento de mostrar elementos por pantalla. Gracias a estas declaraciones es posible invertir los colores de toda la pantalla fácilmente sin cambiar cada elemento uno a uno.

Mostrando textos y formas básicas

Antes de imprimir una cadena de caracteres es necesario declarar la fuente que será usada en el renderizado del texto. Lo más sencillo es utilizar las fuentes de Google gfonts, pero también es posible instalar fuentes de forma local.

font:
  - file:
      type: gfonts
      family: Source Code Pro
      weight: 600
    id: roboto_20
    size: 20
  - file:
      type: gfonts
      family: Source Code Pro
      weight: 800
    id: roboto_26
    size: 26

# Los siguientes ejemplos siguen a la directiva 'lambda: |-'
it.printf(290,   0, id(roboto_20), color_print, "P:%.0fW", id(grid_power_id).state);

it.rectangle(320, 115, 70, 70, color_print);
it.printf(330, 115, id(roboto_20), color_print, "Ext.");
it.printf(327, 140, id(roboto_20), color_print, "%.1f°", id(street_temp_id).state);
it.printf(335, 160, id(roboto_20), color_print, "%.0f%%", id(street_humi_id).state);

El desarrollo de Home-Ambient

Todas las etapas de desarrollo del termostato Home-Ambient se recogen en las siguientes entradas: