<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>Pocho Labs — Blog</title>
    <link>https://www.pocholabs.com.ar/blog/</link>
    <description>Domótica, hardware, self-hosting y proyectos que terminan funcionando en casa.</description>
    <language>es-AR</language>
    <lastBuildDate>Tue, 04 Aug 2026 12:00:00 GMT</lastBuildDate>
    <atom:link href="https://www.pocholabs.com.ar/feed.xml" rel="self" type="application/rss+xml" />
    <image>
      <url>https://www.pocholabs.com.ar/images/pocholabs-logo.png</url>
      <title>Pocho Labs</title>
      <link>https://www.pocholabs.com.ar/blog/</link>
    </image>
    <item>
      <title>Controlá Home Assistant sin internet con Meshtastic: SenseCAP T1000-E y P1 Pro</title>
      <link>https://www.pocholabs.com.ar/blog/yt/2026-08-04-controla-home-assistant-sin-internet-meshtastic-sensecap/</link>
      <guid isPermaLink="true">https://www.pocholabs.com.ar/blog/yt/2026-08-04-controla-home-assistant-sin-internet-meshtastic-sensecap/</guid>
      <description>Cómo usar un SenseCAP Solar Node P1-Pro y un T1000-E con Meshtastic para recibir avisos, consultar estados y controlar luces de Home Assistant sin depender de internet.</description>
      <content:encoded><![CDATA[<p><img src="https://www.pocholabs.com.ar/images/blog/yt/2026-08-04-controla-home-assistant-sin-internet-meshtastic-sensecap.webp" alt="Controlá Home Assistant sin internet con Meshtastic: SenseCAP T1000-E y P1 Pro" /></p>
<p><em>Si se corta internet, controlar nuestra casa a distancia parece completamente imposible. Pero, ¿y si armamos un plan B con Meshtastic para seguir hablando con Home Assistant?</em></p>
<p><a href="https://www.youtube.com/watch?v=dtJ5sbld4t4">Ver video en YouTube</a></p>
<p>Para este proyecto usé dos nodos totalmente distintos pero que se complementan muy bien: el <strong>SenseCAP Solar Node P1-Pro</strong>, que queda fijo en casa, y el <strong>SenseCAP T1000-E</strong>, una tarjeta portátil que puedo llevar encima.</p>
<p>La idea es simple: poder consultar el estado de casa, controlar algunos dispositivos y recibir avisos importantes incluso cuando no hay internet ni señal celular.</p>
<p>Primero que nada, gracias a la gente de <a href="https://openelab.io/">OpenELAB</a> por enviarme los nodos para hacer este proyecto. Es una tienda donde pueden encontrar estos equipos y un montón de productos de electrónica, microcontroladores y dispositivos para proyectos de casa inteligente.</p>
<ul>
<li><a href="https://openelab.io/products/seeed-studio-sensecap-solar-node?sca_ref=11635920.G6BQlw5KQbl">SenseCAP Solar Node P1-Pro</a></li>
<li><a href="https://openelab.io/products/seeed-studio-sensecap-tracker-t1000?sca_ref=11635920.G6BQlw5KQbl">SenseCAP T1000-E Card Tracker</a></li>
</ul>
<h2>Meshtastic explicado simple</h2>
<p>Meshtastic es un sistema de comunicación basado en <strong>LoRa</strong> que no necesita internet ni señal celular. Los nodos se comunican entre sí y forman una red tipo malla: si dos equipos no llegan de manera directa, otros nodos pueden ayudar a repetir el mensaje hasta destino.</p>
<p>No sirve solamente para mandar texto. También permite compartir la ubicación del nodo y, gracias a la integración con Home Assistant, usar esos mensajes para disparar acciones o recibir información de nuestra casa.</p>
<p>Ya había probado Meshtastic en el Cosquín Rock, donde lo usé para comunicarme en un lugar con miles de personas y señal celular prácticamente inexistente. Esta vez quería ir un poco más lejos: conectarlo con mi casa.</p>
<h2>Seeed Studio SenseCAP T1000-E</h2>
<p><img src="https://www.pocholabs.com.ar/images/blog/2026-08-04/sensecap-t1000-e.png" alt="SenseCAP T1000-E"></p>
<table>
<thead>
<tr>
<th>Especificación</th>
<th>SenseCAP T1000-E</th>
</tr>
</thead>
<tbody>
<tr>
<td>Procesador</td>
<td>Nordic nRF52840</td>
</tr>
<tr>
<td>LoRa</td>
<td>Semtech LR1110</td>
</tr>
<tr>
<td>Posicionamiento</td>
<td>GPS integrado</td>
</tr>
<tr>
<td>Batería</td>
<td>700 mAh</td>
</tr>
<tr>
<td>Carga</td>
<td>Conector magnético USB</td>
</tr>
<tr>
<td>Protección</td>
<td>IP65</td>
</tr>
<tr>
<td>Dimensiones</td>
<td>85 × 55 × 6,5 mm</td>
</tr>
<tr>
<td>Peso</td>
<td>32 g</td>
</tr>
<tr>
<td>Sensores</td>
<td>Luz, temperatura, 3 axis</td>
</tr>
</tbody>
</table>
<p>Lo que más me sorprendió es el tamaño. Comparado con el Heltec T114 que usé en el Cosquín, y más todavía si contamos la batería que le había agregado, esto se puede llevar a cualquier lado sin llamar la atención.</p>
<ul>
<li><a href="https://openelab.io/products/seeed-studio-sensecap-tracker-t1000?sca_ref=11635920.G6BQlw5KQbl">Seeed Studio SenseCAP T1000-E Card Tracker (OpenELAB)</a></li>
</ul>
<h2>Seeed Studio SenseCAP Solar Node P1-Pro</h2>
<p><img src="https://www.pocholabs.com.ar/images/blog/2026-08-04/sensecap-p1-pro.png" alt="SenseCAP P1-Pro"></p>
<table>
<thead>
<tr>
<th>Especificación</th>
<th>SenseCAP Solar Node P1-Pro</th>
</tr>
</thead>
<tbody>
<tr>
<td>Panel solar</td>
<td>5 W</td>
</tr>
<tr>
<td>Placa principal</td>
<td>XIAO nRF52840 Plus</td>
</tr>
<tr>
<td>LoRa</td>
<td>Wio-SX1262</td>
</tr>
<tr>
<td>Posicionamiento</td>
<td>XIAO L76K GPS</td>
</tr>
<tr>
<td>Baterías</td>
<td>4 × 18650 de 3350 mAh</td>
</tr>
<tr>
<td>Autonomía sin sol</td>
<td>Más de dos semanas según Seeed Studio</td>
</tr>
</tbody>
</table>
<ul>
<li><a href="https://openelab.io/products/seeed-studio-sensecap-solar-node?sca_ref=11635920.G6BQlw5KQbl">Seeed Studio SenseCAP P1-Pro (OpenELAB)</a></li>
</ul>
<h2>La idea del proyecto</h2>
<p>La arquitectura quedó de esta manera:</p>
<pre><code class="language-text">[T1000-E portátil] ←→ [Red Meshtastic] ←→ [P1-Pro en casa] ←→ [Home Assistant]
</code></pre>
<ul>
<li>El <strong>P1-Pro</strong> queda fijo en la terraza, alimentado por el panel solar y conectado a Home Assistant.</li>
<li>El <strong>T1000-E</strong> viaja conmigo y me permite enviar comandos o recibir avisos.</li>
<li>Home Assistant sigue controlando localmente luces, enchufes, sensores, aires acondicionados y el resto de la casa.</li>
</ul>
<p>Esto permite consultar estados, controlar dispositivos o recibir una alerta por movimiento o corte de internet sin depender de servicios en la nube.</p>
<h2>Configuración inicial de los nodos</h2>
<blockquote>
<p><strong>¡IMPORTANTE!</strong></p>
<p>Si un nodo usa una antena externa, conectala antes de encenderlo. Transmitir sin la carga correcta puede hacer que la etapa de radiofrecuencia trabaje mal, calentarse y terminar dañado.</p>
</blockquote>
<p>Primero configuré la región de radio correspondiente. En Argentina se usa la banda de <strong>915–928 MHz</strong> y, para esta instalación, utilicé la opción de región compatible indicada para el equipo. Siempre revisen la regulación local antes de transmitir.</p>
<p>Después conecté el P1-Pro al WiFi, comprobé que pudiera accederse desde la interfaz web y realicé la configuración inicial del T1000-E desde el teléfono.</p>
<p>Una vez que ambos nodos estaban usando la misma configuración de Meshtastic, hice una prueba de mensajes entre ellos antes de sumar Home Assistant. Conviene separar los problemas: primero verificamos que la radio funcione y después agregamos el resto de las piezas.</p>
<h2>Cómo integrar Meshtastic con Home Assistant</h2>
<p>Como la conexión local del nodo con Home Assistant se realiza por Bluetooth, necesitamos un <strong>Bluetooth Proxy</strong> cerca del P1-Pro. En criollo, un intermediario que recibe Bluetooth y lo lleva a Home Assistant a través del WiFi.</p>
<p>Para eso se puede usar cualquier ESP32 compatible con ESPHome. En mi caso reutilicé el ESP32 del lavadero porque el nodo solar quedó instalado justo encima y ya tenía una conexión estable. Si no viste el video del lavadero, lo tenes <a href="https://www.pocholabs.com.ar/blog/yt/2026-05-05-impresora-wifi-wr703n-openwrt-cups">acá</a>.</p>
<pre><code class="language-text">[P1-Pro Solar Node] ←→ [Proxy Bluetooth] ←→ [Home Assistant]
</code></pre>
<h3>Proxy Bluetooth con ESPHome</h3>
<p>En este apartado les dejo el código parcial que se necesita para agregar la funcionalida a nuestro dispositivo con un ESP32 y con ESPHome instalado o directamente el código completo para un dispositivo nuevo.</p>
<h4>ESPHome - BLE Tracker y Proxy Bluetooh - YAML</h4>
<pre><code class="language-yaml">esp32_ble_tracker:
  scan_parameters:
    active: true
    interval: 320ms
    window: 300ms

bluetooth_proxy:
  active: true
  connection_slots: 3
</code></pre>
<h4>ESPHome - Código completo - YAML</h4>
<pre><code class="language-yaml">esphome:
  name: bt-proxy
  friendly_name: bt-proxy

esp32:
  board: esp32-c6-devkitc-1
  framework:
    type: esp-idf

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "&#x3C;api_key_encryption>"

ota:
  - platform: esphome
    password: "&#x3C;ota_pwd>"

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Bt-Proxy Fallback Hotspot"
    password: "&#x3C;fallback_hotspot_pwd>"

captive_portal:

esp32_ble_tracker:
  scan_parameters:
    active: true
    interval: 320ms
    window: 300ms

bluetooth_proxy:
  active: true
  connection_slots: 3
</code></pre>
<h3>Meshtastic Custom Integration (HACS)</h3>
<p>Necesitamos instalar, desde <strong>HACS</strong>, <a href="https://github.com/meshtastic/home-assistant">la integración custom de Meshtastic</a>.</p>
<p>Cuando reiniciamos Home Assistant, nos va a aparecer el dispositvDurante la configuración activé el Web Client y el TCP Proxy, y limité la creación de destinos de notificación de mensajes directos a los nodos que realmente iba a utilizar.</p>
<p>Con eso Home Assistant comenzó a recibir el evento <code>meshtastic_api_text_message</code> y apareció la acción <code>meshtastic.send_text</code>, que son las dos piezas que usan las automatizaciones.</p>
<h2>Automatizaciones en Home Assistant</h2>
<blockquote>
<p><strong>ANTES DE COPIAR LAS AUTOMATIZACIONES</strong></p>
<p>Los ejemplos siguientes están generalizados para no publicar los identificadores de mi instalación. Antes de usarlos, hay que reemplazar:</p>
<ul>
<li><code>ID_NODO_SOLAR</code> por el identificador del nodo conectado a Home Assistant.</li>
<li><code>ID_NODO_TRACKER</code> por el identificador del T1000-E que enviará y recibirá mensajes.</li>
<li><code>binary_sensor.internet</code> por el sensor que represente el estado de nuestra conexión.</li>
</ul>
<p>También es importante que las luces tengan nombres claros y estén asignadas a las áreas correctas de Home Assistant. La automatización de control usa esos nombres y áreas para saber qué dispositivo tiene que manejar.</p>
</blockquote>
<h3>Notificación de cambio de estado de Internet</h3>
<p>Para saber si se cortó internet uso un sensor de tipo ping contra una IP pública. Lo agregan desde <em><strong>Settings → Devices and Services → Add Integration</strong></em>
<img src="https://www.pocholabs.com.ar/images/blog/2026-08-04/ha-ping-entity.png" alt="Home Assistant - Ping (ICMP) entity"></p>
<p>Si el estado permanece caído durante un minuto, Home Assistant manda un aviso por Meshtastic. Cuando la conexión vuelve y se mantiene estable otro minuto, manda el mensaje de recuperación.</p>
<p>La espera evita que un microcorte de unos segundos nos llene de mensajes.</p>
<pre><code class="language-yaml">alias: Meshtastic - aviso status internet
description: Avisa por Meshtastic cuando internet se corta o vuelve.
triggers:
  - trigger: state
    entity_id: binary_sensor.internet
    to: "off"
    for:
      minutes: 1
    id: internet_caido
  - trigger: state
    entity_id: binary_sensor.internet
    to: "on"
    for:
      minutes: 1
    id: internet_ok
conditions: []
actions:
  - action: meshtastic.send_text
    data:
      ack: false
      from: "ID_NODO_SOLAR"
      to: "ID_NODO_TRACKER"
      text: >-
        {% if trigger.id == 'internet_caido' %}
          Internet caido.
        {% else %}
          Internet restaurado.
        {% endif %}
mode: single
</code></pre>
<h3>Saber el status de las luces encendidas</h3>
<p>El segundo caso sirve para saber qué quedó encendido en casa. Desde el T1000-E mando solamente:</p>
<pre><code class="language-text">status
</code></pre>
<p>Home Assistant revisa todas las entidades del dominio <code>light</code>, se queda con las que están encendidas y las agrupa por área. Además filtra los grupos de luces para no contar dos veces el mismo dispositivo.</p>
<p>La respuesta tiene un formato corto, ideal para Meshtastic:</p>
<pre><code class="language-text">4 luces: Estudio 2, Cocina 1, Patio 1
</code></pre>
<pre><code class="language-yaml">alias: Meshtastic - status luces por zona
description: Responde cuántas luces reales hay encendidas por zona.
triggers:
  - trigger: event
    event_type: meshtastic_api_text_message
    event_data:
      data:
        from: "ID_NODO_TRACKER"
        to:
          node: "ID_NODO_SOLAR"
          channel: null
        gateway: "ID_NODO_SOLAR"
conditions:
  - condition: template
    value_template: >-
      {{ (trigger.event.data.data.message | string | lower | trim) == 'status' }}
actions:
  - delay:
      seconds: 2
  - action: meshtastic.send_text
    data:
      ack: true
      from: "ID_NODO_SOLAR"
      to: "ID_NODO_TRACKER"
      text: >-
        {% set luces = namespace(total=0, zonas={}) %}
        {% for luz in states.light
          | selectattr('state', 'eq', 'on')
          | rejectattr('attributes.entity_id', 'defined')
          | list %}
          {% set zona = area_name(luz.entity_id) or 'Sin zona' %}
          {% set luces.total = luces.total + 1 %}
          {% set luces.zonas = dict(
            luces.zonas,
            **{zona: (luces.zonas.get(zona, 0) + 1)}
          ) %}
        {% endfor %}
        {{ luces.total }} luces:
        {% for zona, cantidad in luces.zonas.items() %}
          {{ zona }} {{ cantidad }}{% if not loop.last %}, {% endif %}
        {% endfor %}
mode: single
</code></pre>
<h3>Controlar luces por zona o individuales desde Meshtastic</h3>
<p>Esta es la más copada. Podemos controlar una luz puntual, todas las luces de una zona o directamente toda la casa.</p>
<p>Algunos ejemplos:</p>
<pre><code class="language-text">luz principal estudio on
luces cocina off
luces off
</code></pre>
<p>La diferencia entre <code>luz</code> y <code>luces</code> es importante:</p>
<ul>
<li><code>luz &#x3C;nombre> on|off</code> busca una entidad por su nombre completo.</li>
<li><code>luces &#x3C;zona> on|off</code> actúa sobre todas las luces del área.</li>
<li><code>luces on|off</code> actúa sobre todas las luces reales de Home Assistant.</li>
</ul>
<p>Antes de ejecutar la acción, la automatización comprueba el estado actual. Si una luz ya estaba apagada y pedimos apagarla, responde que ya estaba así. También avisa si no encuentra el nombre o la zona.</p>
<pre><code class="language-yaml">alias: Meshtastic - controlar luces
description: Controla luces por zona, todas, o una luz puntual desde Meshtastic.
triggers:
  - trigger: event
    event_type: meshtastic_api_text_message
    event_data:
      data:
        from: "ID_NODO_TRACKER"
        to:
          node: "ID_NODO_SOLAR"
          channel: null
        gateway: "ID_NODO_SOLAR"
variables:
  msg: "{{ trigger.event.data.data.message | string }}"
  msg_norm: "{{ msg | lower | trim | replace('_', ' ') }}"
  msg_parts: "{{ msg_norm.split() }}"
  comando: "{{ msg_parts[0] if msg_parts | count > 0 else '' }}"
  accion: "{{ msg_parts[-1] if msg_parts | count >= 2 else '' }}"
conditions:
  - condition: template
    value_template: >-
      {{ msg_parts | count >= 2
         and comando in ['luz', 'luces']
         and accion in ['on', 'off'] }}
actions:
  - variables:
      objetivo: >-
        {{ msg_parts[1:-1] | join(' ') if msg_parts | count > 2 else '' }}
      luces_objetivo: >-
        {% set ns = namespace(ids=[]) %}
        {% for luz in states.light
          | rejectattr('attributes.entity_id', 'defined')
          | list %}
          {% set nombre = (luz.attributes.friendly_name or luz.name or '')
            | lower | trim %}
          {% set zona = (area_name(luz.entity_id) or '') | lower | trim %}
          {% if comando == 'luces' %}
            {% if objetivo == '' or zona == objetivo %}
              {% set ns.ids = ns.ids + [luz.entity_id] %}
            {% endif %}
          {% elif comando == 'luz' and nombre == objetivo %}
            {% set ns.ids = ns.ids + [luz.entity_id] %}
          {% endif %}
        {% endfor %}
        {{ ns.ids }}
      luces_a_cambiar: >-
        {% set ns = namespace(ids=[]) %}
        {% for entity_id in luces_objetivo %}
          {% if states(entity_id) != accion %}
            {% set ns.ids = ns.ids + [entity_id] %}
          {% endif %}
        {% endfor %}
        {{ ns.ids }}
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ luces_a_cambiar | count > 0 and accion == 'on' }}"
        sequence:
          - action: light.turn_on
            target:
              entity_id: "{{ luces_a_cambiar }}"
      - conditions:
          - condition: template
            value_template: "{{ luces_a_cambiar | count > 0 and accion == 'off' }}"
        sequence:
          - action: light.turn_off
            target:
              entity_id: "{{ luces_a_cambiar }}"
  - delay:
      seconds: 2
  - action: meshtastic.send_text
    data:
      ack: false
      from: "ID_NODO_SOLAR"
      to: "ID_NODO_TRACKER"
      text: >-
        {% if luces_objetivo | count == 0 %}
          No encontre {{ 'la luz' if comando == 'luz' else 'luces' }}{% if objetivo != '' %} {{ objetivo }}{% endif %}.
        {% elif luces_a_cambiar | count == 0 %}
          Ya estaba {{ 'encendida' if accion == 'on' else 'apagada' }}{% if comando == 'luz' %}: {{ objetivo }}{% elif objetivo != '' %}: {{ objetivo }}{% else %}: todo{% endif %}.
        {% else %}
          OK, {{ luces_a_cambiar | count }} {{ 'luz' if luces_a_cambiar | count == 1 else 'luces' }} {{ 'encendida' if accion == 'on' else 'apagadas' }}{% if objetivo != '' %}: {{ objetivo }}{% else %}: todo{% endif %}.
        {% endif %}
mode: single
</code></pre>
<h2>Mención para Meshtastic Argentina</h2>
<p>Por último, los invito a que se sumen a la comunidad de <a href="https://mesharg.com.ar/">Meshtastic Argentina</a>. Tienen un grupo de Telegram (<a href="https://t.me/meshtastic_argentina">link</a>). Ahí van a encontrar gente desparramada a lo largo de todo el territorio argentino. Desde coordinar despliegues de nodos por en distintas partes, hasta asistencia en cualquier duda o inconveniente que tengan.</p>
<p>Si llegaste hasta acá, no te olvides de suscribirte al canal.</p>]]></content:encoded>
      <pubDate>Tue, 04 Aug 2026 12:00:00 GMT</pubDate>
      <category>Casa inteligente</category>
      <category>Meshtastic</category>
      <category>Video</category>
      <media:content url="https://www.pocholabs.com.ar/images/blog/yt/2026-08-04-controla-home-assistant-sin-internet-meshtastic-sensecap.webp" medium="image" />
      <media:thumbnail url="https://www.pocholabs.com.ar/images/blog/yt/2026-08-04-controla-home-assistant-sin-internet-meshtastic-sensecap.webp" />
    </item>
    <item>
      <title>Convertí una impresora vieja en WiFi e INTELIGENTE con un mini router, OpenWRT y Home Assistant</title>
      <link>https://www.pocholabs.com.ar/blog/yt/2026-05-05-impresora-wifi-wr703n-openwrt-cups/</link>
      <guid isPermaLink="true">https://www.pocholabs.com.ar/blog/yt/2026-05-05-impresora-wifi-wr703n-openwrt-cups/</guid>
      <description>Cómo conectar una HP LaserJet P1005 a WiFi usando un TP-Link TL-WR703N con OpenWRT, cambio de memoria SPI flash, p910nd, CUPS en contenedor y automatización con Home Assistant.</description>
      <content:encoded><![CDATA[<p><img src="https://www.pocholabs.com.ar/images/blog/yt/2025-05-05-converti-impresora-en-smart.webp" alt="Convertí una impresora vieja en WiFi e INTELIGENTE con un mini router, OpenWRT y Home Assistant" /></p>
<p><em>Cansado de sacar la impresora del armario cada vez que necesitaba imprimir, me acordé de un mini router que tenía guardado y terminé en un proyecto que me llevó bastante más de lo esperado. Pero valió la pena.</em></p>
<p><strong>Todo el detalle está en el video de YouTube, este post es un write-up para el que lo quiera hacer.</strong></p>
<p><a href="https://www.youtube.com/watch?v=BQu5eP-yqM0">Ver video en YouTube</a></p>
<h2>El mini router TP-Link TL-WR703N</h2>
<p>Buscando entre mis cosas, encontré un <strong>TP-Link TL-WR703N</strong>.
Este mini router estaba pensado para compartir internet cuando se usaban los módems 3G USB.</p>
<p><img src="https://www.pocholabs.com.ar/images/blog/2026-05-05/tl-wr703n.png" alt="TP-Link TL-WR703N"></p>
<table>
<thead>
<tr>
<th>Especificaciones</th>
<th>Detalle</th>
</tr>
</thead>
<tbody>
<tr>
<td>CPU</td>
<td>Atheros AR7240 (400 MHz)</td>
</tr>
<tr>
<td>Chipset</td>
<td>Atheros AR9331 (wireless integrada)</td>
</tr>
<tr>
<td>WiFi</td>
<td>802.11 b/g/n 150 Mbps (130 Mbps real)</td>
</tr>
<tr>
<td>Potencia wireless</td>
<td>20 dBm – 100 mW</td>
</tr>
<tr>
<td>Memoria flash</td>
<td>4 MB</td>
</tr>
<tr>
<td>RAM</td>
<td>32 MB</td>
</tr>
<tr>
<td>Dimensiones</td>
<td>5.7 cm × 5.7 cm × 1.8 cm</td>
</tr>
<tr>
<td>Puerto LAN</td>
<td>1</td>
</tr>
<tr>
<td>Puerto USB</td>
<td>1 × USB 2.0</td>
</tr>
<tr>
<td>Alimentación</td>
<td>Micro-USB</td>
</tr>
<tr>
<td>LED</td>
<td>1</td>
</tr>
</tbody>
</table>
<p>El modelo venía con el firmware solo en idioma chino, así que en esa época le instalé <strong>OpenWRT</strong>.
<img src="https://www.pocholabs.com.ar/images/blog/2026-05-05/openwrt-inicial.jpg" alt="TP-Link TL-WR703N"></p>
<p><em>Versión de OpenWRT que tenía instalada el router desde la última vez que lo usé.</em></p>
<p>El problema: <strong>la última versión oficial de OpenWRT para este router es la 19</strong>, porque dejaron de soportar dispositivos con 4MB de almacenamiento. Todo lo que vino después requiere más espacio.</p>
<h2>Cambio de memoria SPI Flash: de 4MB a 16MB</h2>
<p>Para poder instalar versiones más recientes de OpenWRT, tuve que cambiar la <strong>memoria SPI flash</strong> (básicamente el "disco" del router) por una de 16MB.</p>
<p>Para hacer esto, tuve que comprar algunas cosas que no tenía:</p>
<h3>Materiales necesarios</h3>
<ul>
<li><strong>Memoria SPI flash W25Q128FVSIG (16MB)</strong>: el modelo exacto o similares → <a href="https://www.mercadolibre.com.ar/25q128fvsg-w25q128fvsg-25q128-w25q128-memoria-spi-128mb-3v/up/MLAU276703224?pdp_filters=item_id:MLA816195803">Mercado Libre</a></li>
<li><strong>Programador CH341A</strong>: el más barato y que funciona para estas memorias, sirve para leer y escribir el chip → <a href="https://listado.mercadolibre.com.ar/ch341a?sb=all_mercadolibre#D%5BA:ch341a%5D">Mercado Libre</a></li>
<li><strong>Pinzas ESD antiestáticas</strong>: para sujetar el chip al desoldar sin armar desastre → <a href="https://www.mercadolibre.com.ar/pack-x6-pinza-brusela-vetus-esd-antiestatica-esd-10-a-15-set/up/MLAU3557760913">Mercado Libre</a></li>
</ul>
<h3>Adaptar el dump original a la nueva memoria</h3>
<p>Primero tenemos que hacer el dump de la memoria original, utilicé la aplicación oficial del programador CH341A pero recomiendo utilizar <strong>NeoProgrammer</strong> (<a href="https://github.com/GioLangLe/CH341B-NeoProgramer">repo acá</a>) ya que me dió mejores resultados a la hora de la escritura (gracias @FreeForge11 en X por la recomendación).</p>
<p>Una vez guardado el dump, extendemos la partición del firmware para que complete los 16MB de la memoria.
Además, cambiamos el <strong>uboot por el de pepe2k</strong> (<a href="https://github.com/pepe2k/u-boot_mod#how-to-use-it">repo acá</a>), que no es el bootloader original pero es necesario para que tome la nueva memoria.</p>
<p>Para hacer estas modificaciones al binario usé <strong>HxD</strong> (<a href="https://mh-nexus.de/en/hxd/">sitio oficial</a>), un editor hexadecimal que permite editar los archivos byte a byte.</p>
<h2>Compilar OpenWRT 23 para el TL-WR703N</h2>
<p>Agradecimiento a este post que utilicé para hacer la compilación de OpenWRT: <a href="https://hackinggate.com/blog/build-openwrt-22-03-for-tl-wr703n-with-16m-flash">Build OpenWRT 22/23 for TL-WR703N with 16M Flash</a> y también al amigo <a href="https://github.com/cocus">Cocus</a> que estuvo detrás de todo este caos dando una mano.</p>
<p>Compartos los pasos que utilicé en particular del post anterior:</p>
<p>Primero y principal, leer e <a href="https://openwrt.org/docs/guide-developer/build-system/install-buildsystem">instalar lo necesario para OpenWRT</a>.</p>
<p>Una vez que está todo instalado, arrancamos con el procedimiento;</p>
<p><strong>1. Clonar el repositorio de OpenWrt</strong></p>
<pre><code class="language-bash">git clone https://github.com/openwrt/openwrt.git
cd openwrt
</code></pre>
<p><strong>2. Hacer checkout de la versión a compilar</strong></p>
<pre><code class="language-bash">git tag -l
git checkout v23.05.6
</code></pre>
<p>Antes de instalar los feeds, modifiqué el archivo <code>feeds.conf.default</code> con los siguientes registros (los que vienen por defecto funcionan recontra lento):</p>
<pre><code>src-git packages https://github.com/openwrt/packages.git^e59d9ef823bcb581e3939789b4eaeaf900b79759
src-git luci https://github.com/openwrt/luci.git^7ce34fe1a53db10bb9dd0223467f5bb71a29a659
src-git routing https://github.com/openwrt/routing.git^4a06b031dc16628c9b8351ac297ecdbc92695dc2
src-git telephony https://github.com/openwrt/telephony.git^98c8a5aa4624312ed758e2e2b6d4039050a1649d
</code></pre>
<p>Ahora sí instalamos los feeds:</p>
<pre><code class="language-bash">./scripts/feeds update -a
./scripts/feeds install -a
</code></pre>
<p>Verificar que no haya errores de dependencias.</p>
<p><strong>3. Modificar la definición <code>Device/tplink_tl-wr703n</code></strong></p>
<p>Editar el archivo <code>target/linux/ath79/image/tiny-tp-link.mk</code>. Buscar la línea <code>define Device/tplink_tl-wr703n</code> y cambiar <code>$(Device/tplink-4mlzma)</code> por <code>$(Device/tplink-16mlzma)</code> (para memoria de 16MB). El resultado debe quedar así:</p>
<pre><code class="language-makefile">define Device/tplink_tl-wr703n
  $(Device/tplink-16mlzma)
  SOC := ar9331            
  DEVICE_MODEL := TL-WR703N                            
  DEVICE_PACKAGES := kmod-usb-chipidea2
  TPLINK_HWID := 0x07030101
  SUPPORTED_DEVICES += tl-wr703n     
endef
TARGET_DEVICES += tplink_tl-wr703n
</code></pre>
<p><strong>4. Modificar el archivo dts para 16MB de flash</strong></p>
<p>Editar <code>target/linux/ath79/dts/ar9331_tplink_tl-wr703n_tl-mr10u.dtsi</code>:</p>
<ul>
<li>En <code>partition@20000 {</code> cambiar <code>reg = &#x3C;0x20000 0x3d0000>;</code> por <code>reg = &#x3C;0x20000 0xfd0000>;</code></li>
<li>Cambiar <code>art: partition@3f0000 {</code> por <code>art: partition@ff0000 {</code></li>
<li>Debajo de eso, cambiar <code>reg = &#x3C;0x3f0000 0x10000>;</code> por <code>reg = &#x3C;0xff0000 0x10000>;</code></li>
</ul>
<p>El resultado debe quedar así:</p>
<pre><code class="language-dts">&#x26;spi {                  
        status = "okay";
                                             
        flash@0 {                            
                compatible = "jedec,spi-nor";  
                reg = &#x3C;0>;                     
                spi-max-frequency = &#x3C;25000000>;
                                                        
                partitions {                            
                        compatible = "fixed-partitions";
                        #address-cells = &#x3C;1>;
                        #size-cells = &#x3C;1>;  
                                                    
                        uboot: partition@0 {        
                                reg = &#x3C;0x0 0x20000>;
                                label = "u-boot";
                                read-only;
                        };                                     
                                                               
                        partition@20000 {                      
                                compatible = "tplink,firmware";
                                reg = &#x3C;0x20000 0xfd0000>;
                                label = "firmware";
                        };                               
                                                         
                        art: partition@ff0000 {          
                                reg = &#x3C;0xff0000 0x10000>;
                                label = "art";
                                read-only;
                        };
                };
        };
};
</code></pre>
<p><strong>5. Configurar el build</strong></p>
<p>Descargar el <code>config.buildinfo</code> para OpenWrt v23.05.6:</p>
<pre><code class="language-bash">wget https://downloads.openwrt.org/releases/23.05.6/targets/ath79/tiny/config.buildinfo -O config.buildinfo
</code></pre>
<p>Agregar las siguientes líneas al <code>config.buildinfo</code>:</p>
<pre><code>CONFIG_TARGET_DEVICE_ath79_tiny_DEVICE_tl-wr703n-v1=y
CONFIG_TARGET_DEVICE_PACKAGES_ath79_tiny_DEVICE_tl-wr703n-v1=""
</code></pre>
<p>Y estos paquetes que son clave para mi caso del print server:</p>
<pre><code>CONFIG_PACKAGE_kmod-usb-core=y
CONFIG_PACKAGE_kmod-usb-printer=y    # crea /dev/usb/lp0
CONFIG_PACKAGE_p910nd=y              # el print server
CONFIG_PACKAGE_luci-app-p910nd=y     # interfaz web para p910nd
CONFIG_PACKAGE_libusb-1.0=y
</code></pre>
<p>Sobreescribir <code>.config</code> con <code>config.buildinfo</code>. Deberías ver TL-WR703N en la lista de Target Devices:</p>
<pre><code class="language-bash">cat config.buildinfo > .config
make defconfig
make menuconfig
</code></pre>
<p>Antes de hacer el build, les recomiendo destildar la opción <code>Build the LLVM-BPF toolchain tarball</code> ya que a mi me trajo errores a la hora de buildear.
<img src="https://www.pocholabs.com.ar/images/blog/2026-05-05/openwrt-menu-config.png" alt="OpenWRT menuconfig"></p>
<p>Comencemos el build, esto va a tomar bastante tiempo como dice el post original pueden ser bastantes minutos o incluso horas.</p>
<pre><code>nohup time make -j8 V=s &#x26;
</code></pre>
<p>Se puede ver en tiempo real como va el proceso con este comando:</p>
<pre><code>tail -f nohup.out
</code></pre>
<p>Una vez terminado el build, tenemos que subir el firmware al router.</p>
<h3>Flashear el firmware via web (método pepe2k)</h3>
<p>Una de las ventajas del uboot de pepe2k es que incluye un <strong>servidor web integrado</strong> que permite subir el firmware directamente desde el navegador, sin necesidad de consola serie ni servidor TFTP.</p>
<ol>
<li>Conectar el router al PC con un cable de red por el puerto LAN</li>
<li>Configurar la IP del PC manualmente: <code>192.168.1.2</code> con máscara <code>255.255.255.0</code></li>
<li>Encender el router <strong>manteniendo presionado el botón de reset</strong> hasta que el LED parpadee (unos 3 segundos)</li>
<li>Abrir el navegador y entrar a <code>http://192.168.1.1</code></li>
<li>Va a aparecer una página simple con un formulario de carga de archivo</li>
<li>Seleccionar el archivo <code>.bin</code> del firmware compilado (el <code>sysupgrade</code> o <code>factory</code>)</li>
<li>Hacer click en el botón para iniciar la escritura y esperar que el router reinicie solo
<img src="https://www.pocholabs.com.ar/images/blog/2026-05-05/uboot-pepe2k.png" alt="pepe2k-web">
<em>Así se ve la web del uboot de pepe2k para subir el firmware compilado.</em>
Una vez que reinicia ya tiene el nuevo OpenWRT corriendo.</li>
</ol>
<h2>La arquitectura: CUPS + p910nd</h2>
<p>Como el router tiene poca RAM (32MB), desistí con la idea de correr CUPS ahí dentro. La arquitectura final quedó así:
<img src="https://www.pocholabs.com.ar/images/blog/2026-05-05/plan-cups-p910nd.png" alt="Plan final"></p>
<pre><code>[Cliente]  →IPP→  [CUPS / Home Server]  →TCP 9100→  [p910nd / Router]  →USB→  [HP P1005]
</code></pre>
<p><strong>¿Por qué no CUPS directo en el router?</strong></p>
<p>La HP P1005 requiere el driver <strong>foo2zjs</strong>, que a su vez depende de ghostscript para convertir PDF/PS. El binario de ghostscript ocupa ~15MB. El TL-WR703N tiene 4MB de flash total. Es imposible.</p>
<p><strong>¿Qué hace p910nd?</strong></p>
<p><a href="https://p910nd.sourceforge.net/">p910nd</a> es un proxy extremadamente liviano (~15KB, sin dependencias) que hace exactamente una cosa: abre el puerto TCP 9100 y reenvía cada byte que recibe hacia el dispositivo USB configurado (<code>/dev/usb/lp0</code>), y viceversa. No interpreta nada. Es un puente bidireccional puro.</p>
<table>
<thead>
<tr>
<th>Componente</th>
<th>Protocolo</th>
<th>Puerto</th>
</tr>
</thead>
<tbody>
<tr>
<td>CUPS (clientes)</td>
<td>IPP/IPPS</td>
<td>631</td>
</tr>
<tr>
<td>CUPS → p910nd</td>
<td>AppSocket (raw TCP)</td>
<td>9100</td>
</tr>
<tr>
<td>p910nd → impresora</td>
<td>USB printer class</td>
<td>—</td>
</tr>
</tbody>
</table>
<h2>La HP LaserJet P1005 y el firmware correcto</h2>
<p><img src="https://www.pocholabs.com.ar/images/blog/2026-05-05/hp-laserjet-p1005.webp" alt="HP LaserJet P1005"></p>
<p><em>Un cañito esta impresora, vieja pero se la banca.</em></p>
<p>Esta impresora es <strong>host-based</strong> (también llamada GDI o "winprinter"): no tiene procesador ni firmware propio almacenado en ROM. Al conectarla por USB, el sistema operativo del host debe enviarle un archivo de firmware antes de que pueda recibir trabajos de impresión.</p>
<p>El firmware se pierde cada vez que la impresora se desconecta o apaga. Hay que cargarlo de nuevo en cada conexión.</p>
<p>El USB ID de la impresora <strong>nunca cambia</strong> (<code>03f0:3d17</code>). Lo que cambia es el Device ID IEEE 1284:</p>
<pre><code>Sin firmware:  CMD:ACL
Con firmware:  CMD:HBS,PJL,ACL;FWVER:20080415
</code></pre>
<p><strong>La clave estaba en usar el firmware correcto.</strong> Hay dos versiones del archivo <code>sihpP1005.dl</code> dando vueltas:</p>
<table>
<thead>
<tr>
<th>Origen</th>
<th>Tamaño</th>
<th>MD5</th>
<th>Funciona</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>printer-driver-foo2zjs</code></td>
<td>222.443 bytes</td>
<td><code>ed18611a9c0c6c23b97d8c543fb2ec79</code></td>
<td>✓ Sí</td>
</tr>
<tr>
<td>Plugin HPLIP</td>
<td>116.925 bytes</td>
<td><code>63f5696df7175af70cdfbf56126336ce</code></td>
<td>✗ No</td>
</tr>
</tbody>
</table>
<p>El firmware que funciona es el del paquete <strong>foo2zjs</strong> (open source), no el plugin propietario de HPLIP.</p>
<p><strong>Cómo obtenerlo:</strong></p>
<h4>Opción 1: desde un sistema Debian/Ubuntu con el paquete instalado</h4>
<pre><code class="language-bash">sudo apt install printer-driver-foo2zjs
# El archivo queda en: /usr/lib/firmware/hp/sihpP1005.dl
</code></pre>
<h4>Opción 2: descargar con el script del proyecto foo2zjs</h4>
<pre><code class="language-bash">git clone https://github.com/koenkooi/foo2zjs
cd foo2zjs
./getweb P1005
# → crea sihpP1005.dl en el directorio actual
</code></pre>
<p>Verificar siempre el MD5 antes de usar:</p>
<pre><code class="language-bash">md5sum sihpP1005.dl
# debe mostrar: ed18611a9c0c6c23b97d8c543fb2ec79
</code></pre>
<h2>Configurar OpenWRT y p910nd</h2>
<h3>Copiar el firmware de la impresora al router</h3>
<pre><code class="language-bash"># Desde la máquina que tiene el archivo:
scp -O sihpP1005.dl root@IP-DEL-ROUTER:/lib/firmware/sihpP1005.dl

# Verificar en el router:
md5sum /lib/firmware/sihpP1005.dl
# → ed18611a9c0c6c23b97d8c543fb2ec79
</code></pre>
<h3>Configurar p910nd</h3>
<p>Archivo <code>/etc/config/p910nd</code> en el router:</p>
<pre><code class="language-uci">config p910nd
    option device         '/dev/usb/lp0'
    option port           '0'
    option bidirectional  '1'
    option enabled        '1'
    option runas_root     '1'
    option usbvidpid      '03f0/3d17'
    option driver_file    '/lib/firmware/sihpP1005.dl'
</code></pre>
<p>Luego ejecutar:</p>
<pre><code class="language-bash">/etc/init.d/p910nd restart
/etc/init.d/p910nd enable
</code></pre>
<h3>Opciones críticas</h3>
<table>
<thead>
<tr>
<th>Opción</th>
<th>Valor</th>
<th>Por qué</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>bidirectional</code></td>
<td><code>1</code></td>
<td>La P1005 usa protocolo bidireccional. Sin esto, CUPS puede reportar errores falsos.</td>
</tr>
<tr>
<td><code>usbvidpid</code></td>
<td><code>03f0/3d17</code></td>
<td>El USB ID de la P1005. <strong>Nunca</strong> es <code>3e17</code> (ese es el de la P1006). Si está mal, el hotplug nunca dispara.</td>
</tr>
<tr>
<td><code>driver_file</code></td>
<td><code>/lib/firmware/sihpP1005.dl</code></td>
<td>p910nd carga el firmware automáticamente al detectar la impresora vía hotplug.</td>
</tr>
</tbody>
</table>
<p>Al conectar la impresora al router, los logs deben mostrar:</p>
<pre><code>daemon.info p910nd hotplug: Sending driver to p910nd printer 03f0/3d17
daemon.info p910nd hotplug: Sent /lib/firmware/sihpP1005.dl to /dev/usb/lp0 [ 03f0/3d17 ]
daemon.info p910nd hotplug: (Re)starting p910nd
</code></pre>
<pre><code class="language-bash"># Verificar con:
logread | grep p910nd
</code></pre>
<h2>CUPS en un contenedor</h2>
<p>La instalación de CUPS es sencilla; lo tengo corriendo en un contenedor. Uso una <strong>imagen customizada</strong> donde ya dejé preinstalados los drivers foomatic, que son clave para esta impresora:</p>
<p><strong>Repo:</strong> <a href="https://github.com/Pocho-Labs/cups-avahi-airprint">https://github.com/Pocho-Labs/cups-avahi-airprint</a></p>
<p>Ahí también van a encontrar recursos sobre cómo agregar drivers o correrlo como contenedor.</p>
<h3>Configuración de reintentos en CUPS</h3>
<p>Como la impresora y el router están apagados la mayor parte del tiempo, necesitamos que CUPS <strong>reintente el trabajo</strong> mientras todo se está encendiendo. Esto va en <code>/etc/cups/cupsd.conf</code>:</p>
<pre><code class="language-apacheconf">ErrorPolicy retry-job
JobRetryInterval 30
JobRetryLimit 20
</code></pre>
<p>Con esta configuración, CUPS tiene hasta <strong>10 minutos</strong> (20 reintentos × 30 segundos) para que el router levante y cargue el firmware de la impresora antes de descartar el trabajo.</p>
<h3>Agregar la impresora en CUPS</h3>
<p><strong>Por interfaz web</strong> (recomendado para la primera vez):</p>
<ol>
<li>Abrir la interfaz web de CUPS (por defecto en el puerto 631)</li>
<li>Administración → Añadir impresora</li>
<li>Seleccionar <strong>AppSocket/HP JetDirect</strong></li>
<li>En conexión poner: <code>socket://IP-DEL-ROUTER:9100</code></li>
<li>Poner nombre y descripción</li>
<li>Tildar <strong>Compartición</strong></li>
<li>En el último paso seleccionar el driver <code>HP LaserJet P1005 Foomatic/foo2zjs</code> y añadir</li>
</ol>
<h2>Automatización con Home Assistant</h2>
<p>Con todo andando, quería aprovechar y automatizar el encendido. Para eso usé:</p>
<ul>
<li><strong>Enchufe inteligente</strong>: <a href="https://s.click.aliexpress.com/e/_c3L8MvX9">link - ZigBee</a> va conectado a un doble toma donde van la impresora y el router.</li>
<li><strong>Fingerbot</strong>: <a href="https://s.click.aliexpress.com/e/_c3L8MvX9">link - ZigBee</a> dispositivo que hace de "dedo" para presionar el botón físico de encendido de la impresora y se integra fácil a Home Assistant.</li>
</ul>
<p>La lógica es la siguiente: al tener la impresora en la red, Home Assistant la integra mediante CUPS y conoce el estado. Cuando llega un trabajo de impresión, la impresora cambia de <em>En reposo</em> a <em>Imprimiendo</em>.</p>
<p><img src="https://www.pocholabs.com.ar/images/blog/2026-05-05/estado-impresora.png" alt="Estado impresora en HA"></p>
<p>Ahí dispara el script que enciende el enchufe y activa el fingerbot. Una vez que el router levanta y carga el firmware, CUPS reintenta solo imprimir (gracias a la config de reintentos). Luego, cuando la impresora vuelve a <em>En reposo</em> durante 20 minutos, se apaga el enchufe. También dejé un botón en el dashboard para cuando me gana la ansiedad.</p>
<h3>Script: Encender impresora HP LaserJet P1005</h3>
<pre><code class="language-yaml">sequence:
  - action: switch.turn_on
    metadata: {}
    target:
      entity_id: switch.smart_plug
    data: {}
  - delay:
      hours: 0
      minutes: 0
      seconds: 50                 # Un tiempo prudente para que inicie primero el router
      milliseconds: 0
  - action: switch.toggle
    metadata: {}
    target:
      entity_id: switch.fingerbot
    data: {}
    enabled: true
alias: Encender impresora HP LaserJet P1005
description: ""
</code></pre>
<h3>Automatización: Encender impresora en recibir trabajo</h3>
<pre><code class="language-yaml">alias: Encender impresora en recibir trabajo
description: ""
triggers:
  - trigger: state
    entity_id:
      - sensor.hp_laserjet_p1005
    from:
      - idle
    to:
      - printing
conditions:
  - condition: device
    type: is_off
    device_id: device_id_smart_plug
    entity_id: entity_id_smart_plug
    domain: switch
actions:
  - action: script.turn_on
    metadata: {}
    target:
      entity_id: script.encender_impresora
    data: {}
mode: single
</code></pre>
<h3>Automatización: Apagar la impresora inactiva por 20 minutos</h3>
<pre><code class="language-yaml">alias: Apagar la impresora inactiva por 20 minutos
description: ""
triggers:
  - trigger: state
    entity_id:
      - sensor.hp_laserjet_p1005_foomatic_foo2xqx_recommended
    from:
      - printing
    to:
      - idle
    for:
      hours: 0
      minutes: 20
      seconds: 0
conditions:
  - condition: device
    type: is_on
    device_id: device_id_smart_plug
    entity_id: entity_id_smart_plug
    domain: switch
actions:
  - action: switch.turn_off
    metadata: {}
    target:
      entity_id: switch.smart_plug
    data: {}
mode: single
</code></pre>
<p>Espero que les haya sido de utilidad, los leo en los comentarios del video. Sumensé con un like y una suscripción al canal.</p>
<p>Saludos!</p>]]></content:encoded>
      <pubDate>Tue, 05 May 2026 12:00:00 GMT</pubDate>
      <category>Casa inteligente</category>
      <category>Video</category>
      <media:content url="https://www.pocholabs.com.ar/images/blog/yt/2025-05-05-converti-impresora-en-smart.webp" medium="image" />
      <media:thumbnail url="https://www.pocholabs.com.ar/images/blog/yt/2025-05-05-converti-impresora-en-smart.webp" />
    </item>
    <item>
      <title>No más ropa olvidada: CONVERTÍ MI LAVARROPAS EN INTELIGENTE con Home Assistant!</title>
      <link>https://www.pocholabs.com.ar/blog/yt/2025-09-22-lavadero-inteligente/</link>
      <guid isPermaLink="true">https://www.pocholabs.com.ar/blog/yt/2025-09-22-lavadero-inteligente/</guid>
      <description>En este video muestro las automatizaciones que tengo en el lavadero de mi casa para no olvidarme más de colgar la ropa; también muestro otras de las automatizaciones con las luces.</description>
      <content:encoded><![CDATA[<p><img src="https://www.pocholabs.com.ar/images/blog/yt/2025-09-22-lavarropas-inteligente.webp" alt="No más ropa olvidada: CONVERTÍ MI LAVARROPAS EN INTELIGENTE con Home Assistant!" /></p>
<p><em>Tenés un lavarropas común y corriente y te pasa como a mi que lavas y te olvidas sacar la ropa? Seguime que te muestro como!</em></p>
<p><a href="https://www.youtube.com/watch?v=4SlKM5fN1sM">Ver video en YouTube</a></p>
<h2>Entendiendo el comportamiento del lavarropas</h2>
<p>Para comprender como es el funcionamiento, me puse a ver el consumo del lavarropa en sus distintos estados (standby, lavado programado, lavando y apagado).
Para poder generar dichos estados en Home Assistant, tuve que utilizar un <em>template sensor</em> que, dependiendo el consumo que realiza el lavarropas, identifica los estados. Además, tuve que utilizar un <em>input datetime</em> para guardar la hora de encendido del lavarropas, que sirve para poder diferenciar <em>Standby</em> de <em>Lavado programado</em>. Este <em>input datetime</em> se actualiza mediante <a href="#automatizaci%C3%B3n---guardar-hora-de-encendido">esta automatización</a>.</p>
<ul>
<li><strong>Standby</strong>: este estado es cuando encendemos el lavarropas y consume menos de 8w durante un periodo menor a 10 minutos, ya que el modelo de mi lavarropas cuando pasan 10 minutos se apaga automáticamente.</li>
<li><strong>Lavado programado</strong>: cuando el consumo está por debajo de los 8w y ya pasaron 10 minutos de encendido, se considera que está en este estadío esperando a arrancar a lavar.</li>
<li><strong>Lavando</strong>: acá tuve que hacer algo particular, si bien cuando lava consume más de estos 8w, por momentos el consumo baja este umbral y hacía que cambie de estado a programado mientras lavaba. Para solucionar esto, la condición verifica si el estado anterior es Lavando, si esto es así, continúa con dicho estado. La lógica siempre es que de Lavando pasa a apagado, es raro que cancele un lavado.</li>
<li><strong>Apagado</strong>: tan simple como que el consumo es 0w.</li>
</ul>
<p>De paso, guardé algunos atributos para poder hacer troubleshooting más fácilmente y los íconos del <em>template sensor</em> van cambiando dependiendo del estado.</p>
<h3>Código - template sensor</h3>
<pre><code class="language-yaml">template:
  - sensor:
      - name: "Estado Lavarropas"
        unique_id: lavarropas_status
        state: >
          {# Variables #}
          {% set power = states('sensor.lavarropas_power') | float(0) %}
          {% set current_state = states('sensor.lavarropas_status') | default('Apagado') %}
          {% set standby_start =
              states('input_datetime.lavarropas_hora_de_encendido')
              | as_datetime
              | default(now())
              | as_local %}
          {% set minutes_in_standby = (now() - standby_start).total_seconds() / 60 %}

          {# Umbrales #}
          {% set standby_w = 8 %}        {# Consumo máximo para standby/programado #}
          {% set program_delay = 10 %}   {# Minutos para pasar a Lavado programado #}

          {# Logica del estado #}
          {% if power == 0 %}
            Apagado
          {% elif power > standby_w %}
            Lavando
          {% elif 0 &#x3C; power &#x3C;= standby_w %}
            {% if current_state == 'Lavando' %}
              Lavando
            {% elif minutes_in_standby &#x3C; program_delay %}
              Standby
            {% else %}
              Lavado programado
            {% endif %}
          {% endif %}
        attributes:
          current_power: "{{ states('sensor.lavarropas_power') | float(0) }}"
          standby_start_time: "{{ states('input_datetime.lavarropas_hora_de_encendido') }}"
          minutes_in_standby: >
            {% if this.state == 'Apagado' %}
              0
            {% else %}
              {% set ss = states('input_datetime.lavarropas_hora_de_encendido')
                  | as_datetime
                  | default(now())
                  | as_local %}
              {{ (now() - ss).total_seconds() / 60 }}
            {% endif %}
        icon: >
          {% set s = this.state %}
          {% if s == 'Apagado' %}
            mdi:power-plug-off
          {% elif s == 'Standby' %}
            mdi:power-standby
          {% elif s == 'Lavado programado' %}
            mdi:washing-machine-alert
          {% elif s == 'Lavando' %}
            mdi:washing-machine
          {% else %}
            mdi:help-circle
          {% endif %}
</code></pre>
<h3>Automatización - Guardar hora de encendido</h3>
<pre><code class="language-yaml">alias: Lavarropas - Guardar hora de encendido
description: ""
triggers:
  - entity_id: sensor.lavarropas_status
    from: Apagado
    to:
      - Standby
      - Lavando
      - Lavado programado
    trigger: state
actions:
  - data:
      datetime: "{{ now().strftime('%Y-%m-%d %H:%M:%S') }}"
    action: input_datetime.set_datetime
    target:
      entity_id: input_datetime.lavarropas_hora_de_encendido
mode: single
</code></pre>
<h2>Automatizaciones</h2>
<p>Acá tengo una lista variada de automatizaciones, algunas relacionadas al lavarropas y el aviso de cuando termina de lavar, y otras para lo que es la automatización de la luz del lavadero.</p>
<h3>Aviso de colgar ropa</h3>
<p>Para lo que es la notificación recurrente, utilicé un <em>input_boolean</em> que se llama <em>colgar_ropa</em>. Cuando el lavarropas pasa de <em>Lavando</em> a <em>Apagado</em>, cambia el valor a encendido.</p>
<p>Esto lo hago para mantener el estado de <em>colgar_ropa</em> hasta que realmente pase esa acción y desactivar las notificaciones recurrentes con el botón.</p>
<h3>Setear colgar ropa despues del lavado</h3>
<p>Esta automatización además de cambiar el estado a encendido, hace que el led del pulsador se encienda en color azul:</p>
<pre><code class="language-yaml">alias: Setear colgar ropa despues del lavado
description: ""
triggers:
  - trigger: state
    entity_id:
      - sensor.lavarropas_status
    from: Lavando
    to: Apagado
conditions: []
actions:
  - action: input_boolean.turn_on
    metadata: {}
    data: {}
    target:
      entity_id: input_boolean.colgar_ropa
  - action: light.turn_on
    metadata: {}
    data:
      rgb_color:
        - 0
        - 0
        - 255
      brightness_pct: 30
    target:
      entity_id: light.lavadero_led_lavarropas
mode: single
</code></pre>
<h3>Sonar cuando hay ropa para colgar y entro al lavadero</h3>
<p>Esta es la automatización que hace que cada vez que entro al lavadero, suene la melodía de Volver al Futuro y titile el LED.</p>
<pre><code class="language-yaml">alias: Sonar cuando hay ropa para colgar y entro al lavadero
description: ""
triggers:
  - trigger: state
    entity_id:
      - binary_sensor.lavadero_ld2410_presence
    from: "off"
    to: "on"
conditions:
  - condition: state
    entity_id: input_boolean.colgar_ropa
    state: "on"
actions:
  - action: esphome.lavadero_play_song
    metadata: {}
    data: {}
mode: single
</code></pre>
<h3>Notificacion terminó el lavarropas</h3>
<p>Esta automatización es un poco más "compleja" por así decirlo, ya que depende si estoy en casa o no, que notificaciones envía.</p>
<p>Si estoy en casa, cada 10 minutos envía un mensaje a la app de Home Assistant en iOS y además Alexa me notifica lo mismo. Para enviar este tipo de notificaciones utilizo el <em>custom component</em> de <a href="https://github.com/alandtse/alexa_media_player">Alexa Media Player</a>.</p>
<p>Si no estoy en casa, me manda una notificación a la app de Home Assistant de iOS cada media hora.</p>
<pre><code class="language-yaml">alias: Notificacion termino el lavarropas
description: ""
triggers:
  - trigger: state
    entity_id:
      - input_boolean.colgar_ropa
    to: "on"
conditions: []
actions:
  - repeat:
      until:
        - condition: state
          entity_id: input_boolean.colgar_ropa
          state: "off"
      sequence:
        - if:
            - condition: state
              entity_id: person.ezequiel
              state: home
          then:
            - action: notify.mobile_app_itasskkk
              metadata: {}
              data:
                title: Lavarropas
                message: >-
                  Terminó el lavado, andá a colgarla antes que quede arrugada y
                  con olor!
            - action: notify.alexa_media_echo
              metadata: {}
              data:
                message: Pochito, terminó el lavarropas!
            - delay:
                hours: 0
                minutes: 10
                seconds: 0
                milliseconds: 0
          else:
            - repeat:
                until:
                  - condition: zone
                    entity_id: person.ezequiel
                    zone: zone.home
                sequence:
                  - action: notify.mobile_app_itasskkk
                    metadata: {}
                    data:
                      title: Lavarropas
                      message: >-
                        Terminó el lavado, andá a colgarla antes que quede
                        arrugada y con olor!
                  - delay:
                      hours: 0
                      minutes: 30
                      seconds: 0
                      milliseconds: 0
mode: single
</code></pre>
<h3>Apagar el switch despues de lavar</h3>
<pre><code class="language-yaml">alias: Apagar switch despues de lavar
description: ""
triggers:
  - trigger: state
    entity_id:
      - sensor.lavarropas_status
    to: Apagado
    for:
      hours: 0
      minutes: 10
      seconds: 0
conditions: []
actions:
  - action: switch.turn_off
    metadata: {}
    data: {}
    target:
      entity_id: switch.lavarropas
mode: single
</code></pre>
<h3>Enciende la luz del lavadero cuando detecta presencia</h3>
<p>Cuando es de noche y detecta que entro al lavadero, enciende la luz.</p>
<pre><code class="language-yaml">alias: Encende la luz del lavadero cuando detecte presencia
description: ""
triggers:
  - trigger: state
    entity_id:
      - binary_sensor.lavadero_ld2410_presence
    from: "off"
    to: "on"
conditions:
  - condition: sun
    before: sunrise
    after: sunset
    enabled: false
actions:
  - action: light.turn_on
    metadata: {}
    data: {}
    target:
      entity_id: light.lavadero_lavadero
mode: single
</code></pre>
<h3>Apaga la luz del lavadero cuando no hay nadie</h3>
<p>No hay mucha más complejidad en esta automatización, espera 2 minutos luego de cambiar el estado de <em>Detected</em> a <em>Clear</em> para apagar la luz.</p>
<pre><code class="language-yaml">alias: Apaga la luz del lavadero cuando no hay nadie
description: ""
triggers:
  - trigger: state
    entity_id:
      - binary_sensor.lavadero_ld2410_presence
    from: "on"
    to: "off"
    for:
      hours: 0
      minutes: 2
      seconds: 0
conditions: []
actions:
  - action: light.turn_off
    metadata: {}
    data: {}
    target:
      entity_id: light.lavadero_lavadero
mode: single
</code></pre>
<h2>Dispositivo con ESPHome</h2>
<p>Para este proyecto, utilicé un ESP32-C6-Zero. Es un microcontrolador bastante potente, soporta WiFi 6, Bluetooth 5 y soporta el estándar IEEE 802.15.4 - Zigbee 3.0/Thread. Les <a href="https://www.waveshare.com/esp32-c6-zero.htm">comparto el link</a> del fabricante para más info.</p>
<p>Si lo comparamos con el ESP32 más comun que conocemos es muchísimo más chico, casi del tamaño de una moneda:</p>
<p><img src="https://www.pocholabs.com.ar/images/blog/2025-09-22/esp32-c6.webp" alt="Comparativa entre un NodeMCU ESP32-WROOM-32 y el Waveshare ESP32-C6-Zero"></p>
<h3>Componentes</h3>
<p>En el microcontrolador utilicé:</p>
<ul>
<li>Modulo doble de relays (para la luz del lavadero y del pasillo)</li>
<li>Botón pulsador rojo (puede ser cualquier boton)</li>
<li>LED RGB</li>
<li>Buzzer (usé uno típico de PC)</li>
<li>Resistencias 220 Ohms para el LED RGB (1 en cada paga de los colores)</li>
<li>Transistor 2N2222 (para potenciar el sonido del buzzer)</li>
<li>Resistencia de 1k Ohms (conectada a la pata base del transistor)</li>
<li>2 switches típicos de electricidad para controlar los relays de las luces</li>
</ul>
<p>El PCB que usé es una típica placa de desarrollo que se puede cortar a gusto.</p>
<h3>Esquema de conexión</h3>
<p><img src="https://www.pocholabs.com.ar/images/blog/2025-09-22/esp32-esquema.webp" alt="ESPHome 01"></p>
<h3>Como hacemos para que el buzzer reproducza melodías?</h3>
<p>Para que el buzzer reproduzca melodías, debemos utilizar el formato <em>RTTTL</em>. <em>Ring Tone Text Transfer Language</em> es un formato desarrollado por Nokia y que podemos utilizar en nuestros microcontroladores.
En internet hay varios sitios de donde podemos descargar estas cadenas de texto, les dejo los que anduve investigando:</p>
<ul>
<li><a href="http://arcadetones.emuunlim.com/arcade.htm">Arcade Ringtones</a></li>
<li><a href="https://1j01.github.io/rtttl.js">RTTTL Player</a></li>
<li><a href="https://picaxe.com/rtttl-ringtones-for-tune-command/">RTTTL Ringtone downloads</a></li>
<li><a href="https://www.todomovil.net/melodias/rtttl.asp">Todomovil.net</a></li>
</ul>
<p>Si quieren innovar y probar sus propios RTTTL, está <a href="https://adamonsoon.github.io/rtttl-play/">este sitio</a>.</p>
<p>También les dejo la configuración del ESP32 con ESPHome para que puedan crear su propio dispositivo:</p>
<h3>ESPHome - yaml</h3>
<pre><code class="language-yaml">esphome:
  name: lavadero
  friendly_name: lavadero

esp32:
  board: esp32-c6-devkitc-1
  framework:
    type: esp-idf

logger:

api:
  encryption:
    key: !secret lavadero_encryption
  services:
    - service: play_song
      then:
        - script.execute: play_song

ota:
  - platform: esphome
    password: !secret lavadero_ota_pwd

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

  ap:
    ssid: "Lavadero-dev Fallback Hotspot"
    password: "&#x3C;fallback_hotspot_password>"

captive_portal:

output:
  # Buzzer
  - platform: ledc
    pin: GPIO14
    id: buzzer_output
    frequency: 1000Hz
  
  # LED RGB
  - platform: ledc
    pin: GPIO22
    id: led_r
    inverted: true
  - platform: ledc
    pin: GPIO4
    id: led_g
    inverted: true
  - platform: ledc
    pin: GPIO5
    id: led_b
    inverted: true

  # Relays
  - platform: gpio
    pin: GPIO18
    id: relay_pasillo
    inverted: true

  - platform: gpio
    pin: GPIO19
    id: relay_lavadero
    inverted: true

rtttl:
  output: buzzer_output
  id: my_buzzer
  gain: 40%

# Script para reproducir la melodía y alternar colores
script:
  - id: play_song
    then:
      - rtttl.play: "BackToTheFuture:d=16,o=5,b=200:4g.,p,4c.,p,2f#.,p,g.,p,a.,p,8g,p,8e,p,8c,p,4f#,p,g.,p,a.,p,8g.,p,8d.,p,8g.,p,8d6.,p,4d6.,p,4c#6,p,b.,p,c#6.,p,2d6."
      - repeat:
          count: 7
          then:
            - light.turn_on:
                id: led_lavarropas
                red: 50%
                green: 0%
                blue: 0%
                transition_length: 0s
            - delay: 500ms
            - light.turn_on:
                id: led_lavarropas
                red: 0%
                green: 0%
                blue: 50%
                transition_length: 0s
            - delay: 500ms

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO0
      inverted: true
      mode:
        input: true
        pullup: true
    name: "Pulsador"
    internal: true
    on_click:
      - homeassistant.service:
          service: input_boolean.turn_off
          data:
            entity_id: input_boolean.colgar_ropa
      - light.turn_off:
          id: led_lavarropas


  # Interruptores
  - platform: gpio
    pin:
      number: GPIO20
      mode: INPUT_PULLUP
      # inverted: true
    name: "Switch Lavadero"
    internal: true
    on_press:
      - light.toggle: lavadero
    on_release:
      - light.toggle: lavadero

  - platform: gpio
    pin:
      number: GPIO21
      mode: INPUT_PULLUP
      # inverted: true
    name: "Switch Pasillo"
    internal: true
    on_press:
      - light.toggle: pasillo
    on_release:
      - light.toggle: pasillo
  
  # Sensor de presencia LD2410
  - platform: ld2410
    has_target:
      name: "LD2410 Presence"
      id: presence_sensor
    has_moving_target:
      name: "LD2410 Moving Target"
    has_still_target:
      name: "LD2410 Still Target"

uart:
  id: uart_ld2410
  tx_pin: GPIO1
  rx_pin: GPIO3
  baud_rate: 256000

ld2410:
  uart_id: uart_ld2410

sensor:
  - platform: ld2410
    moving_distance:
      name: "LD2410 Moving Distance"
    still_distance:
      name: "LD2410 Still Distance"
    moving_energy:
      name: "LD2410 Moving Energy"
    still_energy:
      name: "LD2410 Still Energy"
    detection_distance:
      name: "LD2410 Detection Distance"

light:
  - platform: rgb
    id: led_lavarropas
    name: "Led Lavarropas"
    red: led_r
    green: led_g
    blue: led_b

  - platform: binary
    name: "Lavadero"
    id: lavadero
    output: relay_lavadero

  - platform: binary
    name: "Pasillo"
    id: pasillo
    output: relay_pasillo
</code></pre>
<p><strong>NOTA IMPORTANTE!</strong></p>
<p>Para que el microcontrolador pueda ejecutar acciones dentro de Home Assistant, tenemos que ir al dispositivo dentro de HA y habilitarle que pueda realizar acciones, sinó la parte de presionar el botón y que cambie el estado de <em>colgar_ropa</em> no va a funcionar.</p>
<p><img src="https://www.pocholabs.com.ar/images/blog/2025-09-22/esphome-01.webp" alt="ESPHome 01"></p>
<p><img src="https://www.pocholabs.com.ar/images/blog/2025-09-22/esphome-02.webp" alt="ESPHome 02"></p>
<h2>Caja</h2>
<p>En breve voy a estar subiendo el diseño de la caja para que puedan descargarlo e imprimirlo.</p>
<p>Espero que les haya gustado este proyecto y les sea de utilidad.
Si tienen alguna duda o sugerencia, los leo en los comentarios del <a href="https://www.youtube.com/watch?v=4SlKM5fN1sM">video</a>!</p>]]></content:encoded>
      <pubDate>Mon, 22 Sep 2025 12:00:00 GMT</pubDate>
      <category>Casa inteligente</category>
      <category>Video</category>
      <media:content url="https://www.pocholabs.com.ar/images/blog/yt/2025-09-22-lavarropas-inteligente.webp" medium="image" />
      <media:thumbnail url="https://www.pocholabs.com.ar/images/blog/yt/2025-09-22-lavarropas-inteligente.webp" />
    </item>
    <item>
      <title>Integrá fácil los aires acondicionados a Home Assistant con el RM4 Mini y SmartIR</title>
      <link>https://www.pocholabs.com.ar/blog/yt/2025-02-12-integra-facil-los-aires-acondicionados-a-home-assistant-con-el-rm4-mini-y-smartir/</link>
      <guid isPermaLink="true">https://www.pocholabs.com.ar/blog/yt/2025-02-12-integra-facil-los-aires-acondicionados-a-home-assistant-con-el-rm4-mini-y-smartir/</guid>
      <description>Con el RM4 Mini y SmartIR, controlá tus aires desde Home Assistant</description>
      <content:encoded><![CDATA[<p><img src="https://www.pocholabs.com.ar/images/blog/yt/2025-02-12-integra-facil-los-aires-acondicionados-a-home-assistant-con-el-rm4-mini-y-smartir.webp" alt="Integrá fácil los aires acondicionados a Home Assistant con el RM4 Mini y SmartIR" /></p>
<p>Hoy quiero mostrarte como podes controlar tu aire acondicionado tradicional desde Home Assistant de una manera muy sencilla y económica.
Para esto vamos a utilizar el control remoto universal de Broadlink, el RM4 Mini y la integración custom SmartIR.</p>
<p>Esta integración nos va a permitir controlar el aire desde Home Assistant y hacer distintas automatizaciones.</p>
<p><a href="https://www.youtube.com/watch?v=R6mcMIFting">Ver video en YouTube</a></p>
<h2>SmartIR</h2>
<p>SmartIR es una integración custom que trae una gran cantidad de códigos IR predefinidos para distintos dispositivos, como aires acondicionados, televisores, luces, etc.
Se instala desde HACS y es muy simple de configurar.</p>
<p>La documentación con el listado de aires acondicionados soportados y sus códigos se encuentra <a href="https://github.com/smartHomeHub/SmartIR/blob/master/docs/CLIMATE.md">acá</a>.</p>
<p>Para realizar la instalación, primero tenemos que agregar el repositorio de SmartIR (<a href="https://github.com/smartHomeHub/SmartIR/">https://github.com/smartHomeHub/SmartIR/</a>) en HACS y luego descargarlo.
Una vez hecho esto, antes de reiniciar, vamos al <em>configuration.yaml</em> y agregamos nuestro dispositivo.</p>
<p>Les dejo el ejemplo de configuración de mi aire, en este caso, Samsung:</p>
<h3>Configuración</h3>
<pre><code class="language-yaml">smartir:
climate:
  - platform: smartir
    name: AC Estudio
    unique_id: estudio_ac
    device_code: 1405 # Código de nuestro aire acondicionado (en mi caso Samsung - lo podés encontrar en la documentación de SmartIR)
    controller_data: remote.rm4_mini_estudio # Nombre de nuestro control remoto
    temperature_sensor: sensor.rm4_mini_estudio_temperature # Opcional
    humidity_sensor: sensor.rm4_mini_estudio_humidity # Opcional
</code></pre>
<h2>Automatizaciones</h2>
<h3>Si se deja una puerta abierta por 10 minutos, cambia el modo del aire de frio a ventilación</h3>
<pre><code class="language-yaml">alias: Puerta abierta - Modo frio a ventilacion
description: ""
triggers:
  - trigger: state
    entity_id:
      - binary_sensor.puerta
    from: "off"
    to: "on"
    for:
      hours: 0
      minutes: 0
      seconds: 10
conditions:
  - condition: state
    entity_id: climate.ac_estudio
    state: cool
actions:
  - action: climate.set_hvac_mode
    metadata: {}
    data:
      hvac_mode: fan_only
    target:
      entity_id: climate.ac_estudio
mode: single
</code></pre>
<h3>Cambiar el modo del aire dependiendo la temperatura</h3>
<p>Esta automatización cambia el modo del aire acondicionado dependiendo la temperatura ambiente. Si la temperatura es menor a 25°C, cambia el modo a ventilación y si es mayor a 29°C, cambia el modo a frío.</p>
<pre><code class="language-yaml">alias: Cambio de modo dependiendo la temperatura
description: ""
triggers:
  - entity_id:
      - climate.ac_estudio
    attribute: current_temperature
    below: 25
    for:
      hours: 0
      minutes: 30
      seconds: 0
      milliseconds: 0
    trigger: numeric_state
  - entity_id:
      - climate.ac_estudio
    attribute: current_temperature
    above: 29
    trigger: numeric_state
conditions:
  - condition: or
    conditions:
      - condition: state
        entity_id: climate.ac_estudio
        state: cool
      - condition: state
        entity_id: climate.ac_estudio
        state: fan_only
actions:
  - choose:
      - conditions:
          - condition: numeric_state
            entity_id: climate.ac_estudio
            attribute: current_temperature
            below: 25
        sequence:
          - data:
              entity_id: climate.ac_estudio
              hvac_mode: fan_only
            action: climate.set_hvac_mode
      - conditions:
          - condition: numeric_state
            entity_id: climate.ac_estudio
            attribute: current_temperature
            above: 29
        sequence:
          - data:
              entity_id: climate.ac_estudio
              hvac_mode: cool
            action: climate.set_hvac_mode
mode: restart
</code></pre>
<h3>Apaga el aire si no hay nadie en casa por 10 minutos</h3>
<pre><code class="language-yaml">alias: Apagar aire fuera de casa
description: ""
triggers:
  - trigger: state
    entity_id:
      - zone.home
    attribute: persons
    to: "0"
    for:
      hours: 0
      minutes: 10
      seconds: 0
conditions:
  - condition: not
    conditions:
      - condition: state
        entity_id: climate.ac_estudio
        state: "off"
actions:
  - action: climate.turn_off
    metadata: {}
    data: {}
    target:
      entity_id: climate.ac_estudio
mode: single

</code></pre>
<p>Espero que les guste y sea de utilidad.
Si tienen alguna duda o sugerencia, te leo en los comentarios!</p>]]></content:encoded>
      <pubDate>Wed, 12 Feb 2025 12:00:00 GMT</pubDate>
      <category>Casa inteligente</category>
      <category>Video</category>
      <media:content url="https://www.pocholabs.com.ar/images/blog/yt/2025-02-12-integra-facil-los-aires-acondicionados-a-home-assistant-con-el-rm4-mini-y-smartir.webp" medium="image" />
      <media:thumbnail url="https://www.pocholabs.com.ar/images/blog/yt/2025-02-12-integra-facil-los-aires-acondicionados-a-home-assistant-con-el-rm4-mini-y-smartir.webp" />
    </item>
    <item>
      <title>Lleva tu impresora 3D a otro nivel con OctoPrint y Home Assistant</title>
      <link>https://www.pocholabs.com.ar/blog/yt/2025-01-08-lleva-tu-impresora-a-otro-nivel-octoprint-homeassistant/</link>
      <guid isPermaLink="true">https://www.pocholabs.com.ar/blog/yt/2025-01-08-lleva-tu-impresora-a-otro-nivel-octoprint-homeassistant/</guid>
      <description>Primer video del canal donde muestro el enchufe inteligente Smart Plug v2 de la marca Athom, que viene preflasheado con ESPHome, ideal para utilizar con Home Assisant ya que se integra localmente a nuestra instalación.</description>
      <content:encoded><![CDATA[<p><img src="https://www.pocholabs.com.ar/images/blog/yt/2025-01-08-lleva-tu-impresora-a-otro-nivel-octoprint-homeassistant.webp" alt="Lleva tu impresora 3D a otro nivel con OctoPrint y Home Assistant" /></p>
<p><em>¿Tenés una impresora 3D y querés aprovecharla al máximo?</em>
<em>En este video te muestro como logré sumarle funcionalidades a mi impresora gracias OctoPrint, un enchufe inteligente y Home Assistant.</em></p>
<p>Desde encenderla desde el celular, calentar la impresora,  que nos notifique por Telegram con una foto de la impresión finalizada o
simplemente que se apague cuando termina de imprimir y detecta que no la vamos a usar más.</p>
<p><a href="https://www.youtube.com/watch?v=JJnBNr0OMm8">Ver video en YouTube</a></p>
<p>Paso a compartir todas las automatizaciones, scripts y comandos RESTful de Home Assistant:</p>
<h2>Automatizaciones</h2>
<h3>Reintentar conectar la impresora a OctoPrint al encender enchufe</h3>
<pre><code class="language-yaml">alias: 3D Printer - Try to connect after turn on
description: ""
triggers:
  - entity_id:
      - &#x3C;switch.nombre_del_switch_conectado_a_la_impresora>
    from: "off"
    to: "on"
    trigger: state
conditions: []
actions:
  - delay:
      hours: 0
      minutes: 3
      seconds: 0
      milliseconds: 0
  - if:
      - condition: state
        entity_id: sensor.octoprint_current_state
        state: unavailable
    then:
      - metadata: {}
        data:
          device_id: &#x3C;device_id>
          profile_name: &#x3C;nombre_del_perfil_de_la_impresora_en_octoprinta>
        action: octoprint.printer_connect
mode: single
</code></pre>
<h3>Apagar impresora al terminar de imprimir</h3>
<p>Esta automatización se encarga de apagar la impresora cuando termina de imprimir y detecta que no la vamos a usar más.</p>
<pre><code class="language-yaml">alias: 3D Printer - Shutdown after print
description: ""
triggers:
  - entity_id:
      - sensor.octoprint_job_percentage
    to: "100.0"
    trigger: state
conditions: []
actions:
  - delay:
      hours: 0
      minutes: 10
      seconds: 0
      milliseconds: 0
  - if:
      - condition: and
        conditions:
          - condition: state
            entity_id: sensor.octoprint_target_tool0_temp
            state: "0.0"
          - condition: state
            entity_id: sensor.octoprint_target_bed_temp
            state: "0.0"
    then:
      - action: switch.turn_off
        metadata: {}
        data: {}
        target:
          entity_id: &#x3C;switch.nombre_del_switch_conectado_a_la_impresora>
mode: single
</code></pre>
<h3>Notificación de Alexa al terminar de imprimir</h3>
<pre><code class="language-yaml">alias: Notification - 3D Printer finished
description: ""
triggers:
  - entity_id:
      - sensor.octoprint_job_percentage
    to: "100.0"
    trigger: state
conditions:
  - condition: time
    after: "09:00:00"
    before: "23:59:00"
actions:
  - metadata: {}
    data:
      message: "\"Pochito, se terminó la impresión 3D\""
    action: &#x3C;notify.nombre_de_tu_dispositivo_alexa_o_que_quieras_que_reciba_la_notificacion>
mode: single
</code></pre>
<h3>Sacar foto y enviar por Telegram al finalizar la impresión</h3>
<pre><code class="language-yaml">alias: Photo OctoPrint to Telegram
description: ""
triggers:
  - entity_id:
      - sensor.octoprint_job_percentage
    to: "100.0"
    trigger: state
conditions: []
actions:
  - variables:
      filename: >-
        /config/www/snapshots/{{ now().strftime('%Y%m%d_%H%M%S') }}_{{
        state_attr('camera.octoprint_camera', 'friendly_name') | slugify }}.jpg
  - action: camera.snapshot
    metadata: {}
    data:
      filename: "{{ filename }}"
    target:
      entity_id: camera.octoprint_camera
  - action: telegram_bot.send_photo
    metadata: {}
    data:
      authentication: digest
      file: "{{ filename }}"
      caption: Terminó la impresión 3D!
mode: single
</code></pre>
<h2>Scripts</h2>
<h3>Calentar impresora</h3>
<pre><code class="language-yaml">alias: Precalentar impresora
sequence:
  - if:
      - condition: state
        entity_id: sensor.octoprint_current_state
        state: Operational
    then:
      - metadata: {}
        data: {}
        action: rest_command.octoprint_set_bed_temp_60
      - metadata: {}
        data: {}
        action: rest_command.octoprint_set_tool_temp_195
      - wait_template: |-
          {{ 
            states('sensor.octoprint_actual_bed_temp')|float >= 59 and 
            states('sensor.octoprint_actual_tool0_temp')|float >= 194 
          }}
        continue_on_timeout: false
        timeout: "00:05:00"
      - metadata: {}
        data:
          message: Impresora lista para imprimir
        action: &#x3C;notify.nombre_de_tu_dispositivo_alexa_o_que_quieras_que_reciba_la_notificacion>
description: ""
icon: mdi:heat-wave
mode: restart
</code></pre>
<h3>Imprimir test de calibracion de la cama</h3>
<p>Este script es valido para enviar cualquier tipo de impresión. Solo hay que cambiar el archivo que se envía.</p>
<pre><code class="language-yaml">alias: Imprimir calibracion
sequence:
  - if:
      - condition: device
        type: is_on
        device_id: &#x3C;device_id>
        entity_id: &#x3C;entity_id>
        domain: switch
      - condition: state
        entity_id: sensor.octoprint_current_state
        state: Operational
    then:
      - action: rest_command.octoprint_set_bed_test_file
        metadata: {}
        data: {}
        response_variable: octoprint_response
      - if:
          - condition: template
            value_template: "{{ octoprint_response['status'] == 204 }}"
        then:
          - action: rest_command.octoprint_start_job
            metadata: {}
            data: {}
    else:
      - action: &#x3C;notify.nombre_de_tu_dispositivo_alexa_o_que_quieras_que_reciba_la_notificacion>
        metadata: {}
        data:
          message: No se pudo imprimir. Verificar el estado de la impresora
description: ""
icon: mdi:printer-3d-nozzle
</code></pre>
<h2>Comandos RESTful</h2>
<p>Para mantener el orden, agrupé todos los comandos en el archivo <code>rest_command.yaml</code>, <strong>recuerden incluirlo en su configuración de Home Assistant.</strong>
Por otra parte, para utilizar la API de OctoPrint necesitamos obtener una API Key. Se obtiene desde OctoPrint, en la parte de User Settings.</p>
<h3>Setear temperatura del fusor a 195°C</h3>
<pre><code class="language-yaml">octoprint_set_tool_temp_195:
    url: https://url_de_octoprint/api/printer/tool
    method: POST
    headers:
      authorization: !secret octoprint_header_api_key
      accept: "application/json, text/html"
      user-agent: 'Mozilla/5.0 {{ useragent }}'
    payload: '{ "command": "target", "targets": { "tool0": 195} }'
    content_type:  'application/json; charset=utf-8'
    verify_ssl: true
</code></pre>
<h3>Setear temperatura de la cama a 60°C</h3>
<pre><code class="language-yaml">octoprint_set_bed_temp_60:
    url: https://url_de_octoprint/api/printer/bed
    method: POST
    headers:
      authorization: !secret octoprint_header_api_key
      accept: "application/json, text/html"
      user-agent: 'Mozilla/5.0 {{ useragent }}'
    payload: '{ "command": "target", "target": 60 }'
    content_type:  'application/json; charset=utf-8'
    verify_ssl: true
</code></pre>
<h3>Enviar archivo de prueba de nivelación de la cama</h3>
<pre><code class="language-yaml">octoprint_set_bed_test_file:
    url: https://url_de_octoprint/api/files/local/Bed%20Level%20Test%20(full).gcode
    method: POST
    headers:
      authorization: !secret octoprint_header_api_key
      accept: "application/json, text/html"
      user-agent: 'Mozilla/5.0 {{ useragent }}'
    payload: '{ "command": "select", "print": true }'
    content_type:  'application/json; charset=utf-8'
    verify_ssl: true
</code></pre>
<h3>Iniciar impresión</h3>
<pre><code class="language-yaml">octoprint_start_job:
    url: https://url_de_octoprint/api/job
    method: POST
    headers:
      authorization: !secret octoprint_header_api_key
      accept: "application/json, text/html"
      user-agent: 'Mozilla/5.0 {{ useragent }}'
    payload: '{ "command": "start" }'
    content_type:  'application/json; charset=utf-8'
    verify_ssl: true
</code></pre>
<h3>Cancelar impresión</h3>
<pre><code class="language-yaml">octoprint_cancel_job:
    url: https://url_de_octoprint/api/job
    method: POST
    headers:
      authorization: !secret octoprint_header_api_key
      accept: "application/json, text/html"
      user-agent: 'Mozilla/5.0 {{ useragent }}'
    payload: '{ "command": "cancel" }'
    content_type:  'application/json; charset=utf-8'
    verify_ssl: true
</code></pre>
<h3>Pausar/Reanudar impresión</h3>
<pre><code class="language-yaml">octoprint_pause_job:
    url: https://url_de_octoprint/api/job
    method: POST
    headers:
      authorization: !secret octoprint_header_api_key
      accept: "application/json, text/html"
      user-agent: 'Mozilla/5.0 {{ useragent }}'
    payload: '{ "command": "pause", "action": "toggle" }'
    content_type:  'application/json; charset=utf-8'
    verify_ssl: true
</code></pre>
<h3>Mover ejes a la posición de home</h3>
<pre><code class="language-yaml">octoprint_home:
    url: https://url_de_octoprint/api/printer/printhead
    method: POST
    headers:
      authorization: !secret octoprint_header_api_key
      accept: "application/json, text/html"
      user-agent: 'Mozilla/5.0 {{ useragent }}'
    payload: '{ "command": "home",  "axes": ["x", "y", "z"]}'
    content_type: 'application/json; charset=utf-8'
    verify_ssl: true  
</code></pre>
<p>Espero que les guste y sea de utilidad.
Si tienen alguna duda o sugerencia, te leo en los comentarios!</p>]]></content:encoded>
      <pubDate>Wed, 08 Jan 2025 12:00:00 GMT</pubDate>
      <category>Casa inteligente</category>
      <category>Impresion 3D</category>
      <category>Video</category>
      <media:content url="https://www.pocholabs.com.ar/images/blog/yt/2025-01-08-lleva-tu-impresora-a-otro-nivel-octoprint-homeassistant.webp" medium="image" />
      <media:thumbnail url="https://www.pocholabs.com.ar/images/blog/yt/2025-01-08-lleva-tu-impresora-a-otro-nivel-octoprint-homeassistant.webp" />
    </item>
    <item>
      <title>Así convertí los ventiladores de techo en smart con el iFan03 de Sonoff</title>
      <link>https://www.pocholabs.com.ar/blog/yt/2024-11-04-asi-converti-mis-ventiladores-en-smart-sonoff-ifan-03/</link>
      <guid isPermaLink="true">https://www.pocholabs.com.ar/blog/yt/2024-11-04-asi-converti-mis-ventiladores-en-smart-sonoff-ifan-03/</guid>
      <description>Primer video del canal donde muestro el enchufe inteligente Smart Plug v2 de la marca Athom, que viene preflasheado con ESPHome, ideal para utilizar con Home Assisant ya que se integra localmente a nuestra instalación.</description>
      <content:encoded><![CDATA[<p><img src="https://www.pocholabs.com.ar/images/blog/yt/2024-11-04-asi-converti-mis-ventiladores-en-smart-sonoff-ifan-03.webp" alt="Así convertí los ventiladores de techo en smart con el iFan03 de Sonoff" /></p>
<p>En estos dos videos quiero compartir como logré convertir todos los ventiladores de casa en smart con el iFan03 de Sonoff.</p>
<p>Si bien estos dispositivos se pueden controlar e integrar a Home Assistant con eWeLink, prefiero utilizar un firmware alternativo como Tasmota para tener un control local y total de los dispositivos.</p>
<p>Como es un tema no menor, separé el video en dos partes para que puedan ver todas las funcionalidades del iFan03 y luego, si soy un poco más tryhard, flashear el dispositivo con Tasmota.</p>
<h2>Videos</h2>
<h3>Así convertí los ventiladores de techo en smart con el iFan03 de Sonoff</h3>
<p><a href="https://www.youtube.com/watch?v=BFrSrkpcU7s">Ver video en YouTube</a></p>
<h3>Flasheo del iFan03 con Tasmota</h3>
<p><a href="https://www.youtube.com/watch?v=aPUmGxC9Fy8">Ver video en YouTube</a></p>
<h2>Diseño para caja de luz rectangular</h2>
<p>Además, hice un diseño para poder colocar el iFan en la caja de la luz tipo rectangular (típicamente usada en Argentina) para poder hacer uso del botón de encendido y que quede todo prolijo.
Comparto el link al diseño en Thingiverse por si les interesa imprimirlo.
<img src="https://www.pocholabs.com.ar/images/blog/2024-11-04/Sonoff_iFan03_iFan04_wall_mount_03.webp" alt="Diseño">
<a href="https://www.thingiverse.com/thing:6799296"><strong>Link a Thingiverse</strong></a></p>
<p><strong>Agradecimientos a <a href="https://tasmota.github.io/docs/">Estudio Tangente</a> por ser mi gurú en el mundo del diseño 3D.</strong></p>
<p>Espero que les guste y sea de utilidad.
Si tienen alguna duda o sugerencia, no duden en dejar un comentario.</p>]]></content:encoded>
      <pubDate>Mon, 04 Nov 2024 12:00:00 GMT</pubDate>
      <category>Casa inteligente</category>
      <category>Video</category>
      <media:content url="https://www.pocholabs.com.ar/images/blog/yt/2024-11-04-asi-converti-mis-ventiladores-en-smart-sonoff-ifan-03.webp" medium="image" />
      <media:thumbnail url="https://www.pocholabs.com.ar/images/blog/yt/2024-11-04-asi-converti-mis-ventiladores-en-smart-sonoff-ifan-03.webp" />
    </item>
    <item>
      <title>Enchufe inteligente con ESPHome, es el ideal para Home Assistant?</title>
      <link>https://www.pocholabs.com.ar/blog/yt/2024-08-12-athom-smart-plug-v2-es-el-enchufe-ideal-para-ha/</link>
      <guid isPermaLink="true">https://www.pocholabs.com.ar/blog/yt/2024-08-12-athom-smart-plug-v2-es-el-enchufe-ideal-para-ha/</guid>
      <description>Primer video del canal donde muestro el enchufe inteligente Smart Plug v2 de la marca Athom, que viene preflasheado con ESPHome, ideal para utilizar con Home Assisant ya que se integra localmente a nuestra instalación.</description>
      <content:encoded><![CDATA[<p><img src="https://www.pocholabs.com.ar/images/blog/yt/2024-08-12-athom-smart-plug-v2-es-el-enchufe-ideal-para-ha.webp" alt="Enchufe inteligente con ESPHome, es el ideal para Home Assistant?" /></p>
<p><em>El Smart Plug v2 de la marca Athom, que viene preflasheado con ESPHome, ideal para utilizar con Home Assisant ya que se integra localmente a nuestra instalación.</em></p>
<p><a href="https://www.youtube.com/watch?v=69jaPyLc3lM">Ver video en YouTube</a></p>]]></content:encoded>
      <pubDate>Mon, 12 Aug 2024 12:00:00 GMT</pubDate>
      <category>Casa inteligente</category>
      <category>Video</category>
      <media:content url="https://www.pocholabs.com.ar/images/blog/yt/2024-08-12-athom-smart-plug-v2-es-el-enchufe-ideal-para-ha.webp" medium="image" />
      <media:thumbnail url="https://www.pocholabs.com.ar/images/blog/yt/2024-08-12-athom-smart-plug-v2-es-el-enchufe-ideal-para-ha.webp" />
    </item>
    <item>
      <title>Hace tu casa inteligente con Home Assistant - Guía de instalación</title>
      <link>https://www.pocholabs.com.ar/blog/yt/2024-09-10-hace-tu-casa-inteligente-con-ha-guia/</link>
      <guid isPermaLink="true">https://www.pocholabs.com.ar/blog/yt/2024-09-10-hace-tu-casa-inteligente-con-ha-guia/</guid>
      <description>Conocé sobre Home Assistant, sus alternativas y por qué lo prefiero sobre el resto.</description>
      <content:encoded><![CDATA[<p><img src="https://www.pocholabs.com.ar/images/blog/yt/2024-09-10-hace-tu-casa-inteligente-con-ha-guia.webp" alt="Hace tu casa inteligente con Home Assistant - Guía de instalación" /></p>
<p><em>Conocé sobre Home Assistant, sus alternativas y por qué lo prefiero sobre el resto.</em>
<em>Además te muestro rápidamente como podes hacer para instalarlo dentro de una Raspberry Pi y comenzar en este mundo del hogar inteligente.</em></p>
<p><a href="https://www.youtube.com/watch?v=5BY65yhNlL4">Ver video en YouTube</a></p>]]></content:encoded>
      <pubDate>Mon, 12 Aug 2024 12:00:00 GMT</pubDate>
      <category>Casa inteligente</category>
      <category>Video</category>
      <media:content url="https://www.pocholabs.com.ar/images/blog/yt/2024-09-10-hace-tu-casa-inteligente-con-ha-guia.webp" medium="image" />
      <media:thumbnail url="https://www.pocholabs.com.ar/images/blog/yt/2024-09-10-hace-tu-casa-inteligente-con-ha-guia.webp" />
    </item>
  </channel>
</rss>
