«Abierto/Cerrado» en la app Shelly: el final de carrera en un componente virtual

Quien monta un Shelly 1 Gen3 en una puerta con un final de carrera en el Add-on acaba preguntando lo mismo: ¿cómo hago que la app diga «Abierto» y «Cerrado» en vez de «Encendido» y «Apagado»? Se puede, pero no donde se busca primero.

Ese interruptor es el relé, no la puerta

El toggle «Encendido/Apagado» es switch:0, la salida de relé que da el pulso al motor. La app no deja renombrar su estado, y no debería: el relé solo sabe que ha dado una orden, no si la puerta llegó a abrirse. La posición real la da el final de carrera cableado a DIGITAL IN del Plus Add-on, que el equipo expone como input:100.

http://<ip>/rpc/Input.GetStatus?id=100

Esa entrada tiene que estar configurada como interruptor (type: "switch"), no como pulsador: un interruptor tiene state —cerrado o abierto, ahora mismo—; un pulsador solo emite eventos de pulsación y no hay estado que mostrar. Si el estado sale al revés, invierte la entrada en su configuración:

http://<ip>/rpc/Input.SetConfig?id=100&config={"invert":true}

A partir de ahí hay dos formas de mostrarlo.

Opción A, sin código: la entrada como sensor de puerta

En la app Shelly Smart Control, abre el Shelly 1 Gen3, añade el periférico de entrada digital y, si tu versión lo ofrece, elige el tipo puerta/garaje. El estado aparece como una tarjeta con su icono y el texto de abierto/cerrado. Haz un ciclo completo para confirmar el sentido. Si la app no ofrece ese tipo, verás un contacto genérico activo/inactivo: entonces, la opción B.

Opción B, texto exacto: Boolean virtual + script

Los Gen3, y los Gen2/Plus con firmware actual, tienen Componentes Virtuales. Un boolean virtual tiene dos títulos —el del estado falso y el del verdadero— y una vista de etiqueta: justo una tarjeta que dice «Cerrado» o «Abierto». Se crea desde Componentes en la app o por RPC, y los virtuales se numeran desde 200:

http://<ip>/rpc/Virtual.Add?type="boolean"&config={"name":"Puerta","meta":{"ui":{"view":"label","titles":["Cerrado","Abierto"]}}}

El orden de titles es [falso, verdadero]. La respuesta devuelve el id; si es otro que 200, ajústalo en el script. Después, en Ajustes → Scripts, crea uno con este código, márcalo para ejecutar al arrancar y actívalo:

// Copia el final de carrera (input:100) a un Boolean virtual (boolean:200)
let ENTRADA  = 100;    // entrada digital del Add-on
let BOOLEANO = 200;    // Componente Virtual «Puerta»
let INVERTIR = false;  // true si sale al revés

function copia(estado) {
  Shelly.call("Boolean.Set", { id: BOOLEANO, value: INVERTIR ? !estado : estado });
}

// Estado al arrancar el script
Shelly.call("Input.GetStatus", { id: ENTRADA }, function (r) {
  if (r) copia(r.state);
});

// Cada cambio del final de carrera
Shelly.addStatusHandler(function (e) {
  if (e.component === "input:" + ENTRADA && e.delta && e.delta.state !== undefined) {
    copia(e.delta.state);
  }
});

Hace dos cosas: copia el estado actual al arrancar —si no, la tarjeta mostraría un valor viejo hasta el primer movimiento— y, después, cada cambio de input:100 que le llega por el manejador de estado. Todo en local: sin internet, la tarjeta sigue al día. Por último, añade el Boolean a un grupo para que aparezca en la pantalla de inicio de la app.

Comprobaciones

  • Ciclo completo de apertura y cierre: la tarjeta tiene que pasar de «Cerrado» a «Abierto» y volver. Un final de carrera mal alineado no llega a marcar.
  • El toggle sigue siendo útil: es el que abre y cierra. Relé y estado son independientes.
  • Si no ves la sección Componentes, actualiza el firmware.

Preguntas frecuentes

¿Puedo renombrar el «Encendido/Apagado» del relé?

No, y aunque pudieras sería engañoso: el relé encendido no garantiza que la puerta esté abierta.

¿Qué ID tiene la entrada del Add-on?

Normalmente input:100. Compruébalo en Componentes o con Shelly.GetComponents.

Resumen: el estado es input:100 en modo interruptor, no el relé; un boolean virtual con titles: ["Cerrado","Abierto"] y un script que copia uno en otro, al arrancar y en cada cambio.