Integrar la Inkplate 10 en HA

Integrar la Inkplate 10 en HA

Si andabas buscando una gran pantalla de tinta electrónica para tus paneles, en esta guía te enseño a integrar la Inkplate 10 en HA.

Pantallas de tinta electrónica

Hace poco configuré mi primera pantalla de tinta electrónica en Home Assistant, usando ESPHome. En ese proyecto utilizamos un display de 4.2″ y salió tan bien que había que llevarlo «a la gran pantalla» (nunca mejor dicho).

La Inkplate 10 es una pantalla de tinta electrónica de grandes dimensiones (9.7″ y 1200 x 820 pixels), frecuencia de actualización de 1.61s, modo de escala de grises y compatibilidad con actualizaciones parciales. Funciona sobre una ESP32, con WiFi y Bluetooth. Incorpora lector de tarjetas microSD, GPIO adicionales y tiene soporte para I²C y SPI.

Todo ello la convierten en el dispositivo perfecto si te habías encaprichado con esconder un panel de control en un cuadro, porque queda genial.

Requisitos previos

Para integrar la Inkplate 10 en HA previamente necesitas:

Configuración de ESPHome

Ahora tenemos que ‘flashear’ la pantala con ESPHome y la configuración correspondiente, que vamos a extraer directamente de la documentación sobre el componente Inkplate. Para ello sigue estos pasos:

  1. Conecta la pantalla a tu ordenador a través del puerto USB-C, usando el cable que viene con la misma.
  2. En Home Assistant, accede al complemento de ESPHome desde el menú lateral y pulsa en “New device”. Pulsa en “Continue” y dale un nombre (por ejemplo, “Inkplate”).
  3. Pulsa en “Next” y a continuación selecciona la opción “ESP32” como tipo de dispositivo. Verás que en el fondo se ha creado un nuevo dispositivo.
  4. Pulsa en “Skip” y haz clic en el enlace “Edit” del bloque correspondiente al dispositivo que acabas de crear.
  5. Añade las siguientes líneas al final del código.
captive_portal:

i2c: 

time:
  - platform: pcf85063
    id: esptime
    # repeated synchronization is not necessary unless the external RTC
    # is much more accurate than the internal clock
    update_interval: never
  - platform: homeassistant
    # instead try to synchronize via network repeatedly ...
    on_time_sync:
      then:
        # ... and update the RTC when the synchronization was successful
        pcf85063.write_time:

pca6416a:
  - id: pca6416a_hub
    address: 0x20
    # Primary expander for display control and additional I/O
  - id: pca6416a_hub2
    address: 0x21
    # Secondary expander for additional I/O

switch:
  - platform: gpio
    id: battery_read_mosfet
    pin:
      pca6416a: pca6416a_hub
      number: 9

sensor:
  - platform: adc
    id: battery_voltage
    update_interval: never
    attenuation: 12db
    pin: 35
  - platform: template
    name: "Inkplate Battery Voltage"
    unit_of_measurement: "V"
    accuracy_decimals: 3
    lambda: |-
      // Enable MOSFET to connect battery voltage divider
      id(battery_read_mosfet).turn_on();
      // Wait for voltage to stabilize
      delay(5);
      // Sample ADC value
      float adc = id(battery_voltage).sample();
      // Disable MOSFET to save power
      id(battery_read_mosfet).turn_off();
      return adc;
    filters:
      - multiply: 2 # Compensate for voltage divider (1:2 ratio)

display:
  - platform: inkplate6
    id: inkplate_display
    greyscale: false
    partial_updating: false
    update_interval: 60s
    model: inkplate_10
    lambda: |-
      it.fill(COLOR_WHITE);  // Fondo blanco
      it.printf(20, 100, id(my_font), COLOR_BLACK, "Hola, aguacateros!");

    ckv_pin: 32
    sph_pin: 33
    gmod_pin:
      pca6416a: pca6416a_hub
      number: 1
    gpio0_enable_pin:
      pca6416a: pca6416a_hub
      number: 8
    oe_pin:
      pca6416a: pca6416a_hub
      number: 0
    spv_pin:
      pca6416a: pca6416a_hub
      number: 2
    powerup_pin:
      pca6416a: pca6416a_hub
      number: 4
    wakeup_pin:
      pca6416a: pca6416a_hub
      number: 3
    vcom_pin:
      pca6416a: pca6416a_hub
      number: 5

font:
  - file: "gfonts://Roboto"
    id: my_font
    size: 80
  1. Cuando hayas terminado de editar el código pulsa en “Save” e “Install”. Selecciona la opción “Manual download” y espera a que el código se compile.
  2. Cuando termine, selecciona la opción “Modern format” para descargar el fichero ‘.bin’ correspondiente.
  3. Ahora ve a la página de ESPHome y pulsa en “Connect”. En la ventana emergente selecciona tu placa y pulsa en “Conectar”.
  4. Ahora pulsa en “Install” y selecciona el fichero ‘.bin’ obtenido en el paso 7. De nuevo, pulsa en “Install”.
  1. Vuelve a Home Assistant y ve a Configuración > Dispositivos y servicios. Lo normal es que tu dispositivo haya sido descubierto y aparezca en la parte superior, esperando únicamente a que pulses el botón de “Configurar”. De lo contrario pulsa en el botón de “Añadir integración”, busca “ESPHome” e introduce la IP de tu placa en el campo ‘Host’. Como siempre, te recomiendo que asignes una IP fija en tu router para evitar fallos en el futuro si esta cambia.
  2. Tras esperar unos segundos deberías ver el siguiente mensaje en pantalla. A partir de aquí, los resultados dependen de tu creatividad!

Ejemplo práctico

Como siempre, tras integrar la Inkplate 10 en HA, lo primero que he hecho es ponerme a diseñar un panel de ejemplo. Aprovechando las grandes dimensiones de la pantalla, esta vez he querido utilizarla para crear un «cuadro inteligente».

substitutions:

# Device customization
# Personalización del dispositivo

  name: inkplate
  friendly_name: Inkplate

  main_image: https://aguacatec.es/wp-content/uploads/2025/04/eink-1.jpg

# Entities / Entidades

  sensor_temperature: sensor.openweathermap_temperature
  sensor_home_temperature: sensor.home_temperatura
  sensor_home_humidity: sensor.home_humedad

  calendar: calendar.aguacatec

# Other settings / Otros ajustes

  allowed_characters: " ¿?¡!#%'()+,-./:°0123456789ABCDEFGHIJKLMNOPQRSTUVWYZabcdefghijklmnopqrstuvwxyzáéíóú"

################################################################################################################


esphome:
  name: ${name}
  friendly_name: ${friendly_name}

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "st+Y49mRdasffds5445L7UeFNS34534fdu5U="

ota:
  - platform: esphome
    password: "sdffsd0f904e6da9ca5fe3243244"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Inkplate Fallback Hotspot"
    password: "Stdsfsdf543Rrp"

captive_portal:

i2c: 

time:
  - platform: pcf85063
    id: esptime
    # repeated synchronization is not necessary unless the external RTC
    # is much more accurate than the internal clock
    update_interval: never
  - platform: homeassistant
    # instead try to synchronize via network repeatedly ...
    on_time_sync:
      then:
        # ... and update the RTC when the synchronization was successful
        pcf85063.write_time:

pca6416a:
  - id: pca6416a_hub
    address: 0x20
    # Primary expander for display control and additional I/O
  - id: pca6416a_hub2
    address: 0x21
    # Secondary expander for additional I/O

switch:
  - platform: gpio
    id: battery_read_mosfet
    pin:
      pca6416a: pca6416a_hub
      number: 9

sensor:
  - platform: adc
    id: battery_voltage
    update_interval: never
    attenuation: 12db
    pin: 35
  - platform: template
    name: "Inkplate Battery Voltage"
    unit_of_measurement: "V"
    accuracy_decimals: 3
    lambda: |-
      // Enable MOSFET to connect battery voltage divider
      id(battery_read_mosfet).turn_on();
      // Wait for voltage to stabilize
      delay(5);
      // Sample ADC value
      float adc = id(battery_voltage).sample();
      // Disable MOSFET to save power
      id(battery_read_mosfet).turn_off();
      return adc;
    filters:
      - multiply: 2 # Compensate for voltage divider (1:2 ratio)

  - platform: homeassistant
    id: sensor_temperature
    entity_id: ${sensor_temperature}
    internal: true
  - platform: homeassistant
    id: sensor_home_temperature
    entity_id: ${sensor_home_temperature}
    internal: true
  - platform: homeassistant
    id: sensor_home_humidity
    entity_id: ${sensor_home_humidity}
    internal: true

text_sensor:
  - platform: homeassistant
    id: calendar_event
    entity_id: ${calendar}
    attribute: message
    internal: true
  - platform: homeassistant
    id: calendar_time
    entity_id: ${calendar}
    attribute: start_time
    internal: true

font:
  - file: "gfonts://Lobster"
    id: font_title
    size: 90
    glyphs: ${allowed_characters}
  - file: "gfonts://Lobster"
    id: font_subtitle
    size: 35
    glyphs: ${allowed_characters}
  - file: "gfonts://Kanit"
    id: font_data
    size: 40
    glyphs: ${allowed_characters}

  - file: "gfonts://Kanit"
    id: font_day
    size: 70
    glyphs: ${allowed_characters}
  - file: "gfonts://Kanit"
    id: font_date
    size: 20
    glyphs: ${allowed_characters}

  - file: "gfonts://Exo 2"
    id: font_calendar
    size: 40
    glyphs: ${allowed_characters}
  - file: "gfonts://Raleway"
    id: font_event
    size: 25
    glyphs: ${allowed_characters}

image:
  - file: mdi:weather-partly-cloudy
    id: icon_temperature
    resize: 50x50
    type: BINARY
    transparency: chroma_key
  - file: mdi:home-thermometer
    id: icon_home_temperature
    resize: 50x50
    type: BINARY
    transparency: chroma_key
  - file: mdi:water-percent
    id: icon_humidity
    resize: 50x50
    type: BINARY
    transparency: chroma_key

  - file: ${main_image}
    id: wallpaper
    resize: 900x564
    type: BINARY
    transparency: chroma_key

  - file: mdi:calendar-blank
    id: icon_calendar
    resize: 200x200
    type: BINARY
    transparency: chroma_key

display:
  - platform: inkplate6
    id: inkplate_display
    greyscale: false
    partial_updating: false
    update_interval: 60s
    model: inkplate_10
    rotation: 270 
    lambda: |-
      it.fill(Color::BLACK); 

      it.printf(410, 120, id(font_title), TextAlign::CENTER, "Home, Sweet Home");
      it.printf(580, 160, id(font_subtitle), "Assistant");

      it.image(80, 200, id(icon_temperature));
      it.printf(140, 195, id(font_data), "%.0f°C", id(sensor_temperature).state);
      it.image(215, 200, id(icon_home_temperature));
      it.printf(275, 195, id(font_data), "%.0f°C", id(sensor_home_temperature).state);
      it.image(365, 200, id(icon_humidity));
      it.printf(415, 195, id(font_data), "%.0f%%", id(sensor_home_humidity).state);

      it.image(-20, 330, id(wallpaper));

      it.image(50, 950, id(icon_calendar));
      it.strftime(150, 1050, id(font_day), TextAlign::CENTER, "%d", id(esptime).now());
      it.strftime(150, 1088, id(font_date), TextAlign::CENTER, "%b / %y", id(esptime).now());

      if (id(calendar_time).state.length() >= 16) {
          std::string date = id(calendar_time).state.substr(8, 2);  // Extrae el día (DD)
          std::string month = id(calendar_time).state.substr(5, 2); // Extrae el mes (MM)
          std::string hour = id(calendar_time).state.substr(11, 2); // Extrae la hora (HH)
          std::string minute = id(calendar_time).state.substr(14, 2); // Extrae los minutos (MM)
          
          // Mapea el número del mes a su nombre en español
          std::map<std::string, std::string> month_names = {
              {"01", "enero"}, {"02", "febrero"}, {"03", "marzo"}, {"04", "abril"},
              {"05", "mayo"}, {"06", "junio"}, {"07", "julio"}, {"08", "agosto"},
              {"09", "septiembre"}, {"10", "octubre"}, {"11", "noviembre"}, {"12", "diciembre"}
          };
          
          std::string month_name = month_names[month]; // Obtiene el nombre del mes
          
          // Imprime el evento y la fecha formateada
          it.printf(250, 1010, id(font_calendar), "%s", id(calendar_event).state.c_str());
          it.printf(250, 1060, id(font_event), "Tendrá lugar el %s de %s, a las %s:%sh", date.c_str(), month_name.c_str(), hour.c_str(), minute.c_str());
      }

    ckv_pin: 32
    sph_pin: 33
    gmod_pin:
      pca6416a: pca6416a_hub
      number: 1
    gpio0_enable_pin:
      pca6416a: pca6416a_hub
      number: 8
    oe_pin:
      pca6416a: pca6416a_hub
      number: 0
    spv_pin:
      pca6416a: pca6416a_hub
      number: 2
    powerup_pin:
      pca6416a: pca6416a_hub
      number: 4
    wakeup_pin:
      pca6416a: pca6416a_hub
      number: 3
    vcom_pin:
      pca6416a: pca6416a_hub
      number: 5