Documentação

Botões e relés no GPIO

Ligue um botão de pressão, um contato de porta ou uma placa de relé aos pinos GPIO de uma tela, e o aplicativo na tela recebe o botão, aciona o relé e informa ao seu agente.

O que o GPIO faz

As linhas GPIO (entrada/saída de uso geral) são os pinos da placa de um Player que um aplicativo pode ler e acionar um a um. Uma linha é uma entrada que lê alto ou baixo, ou uma saída que o aplicativo define como alta ou baixa.

As entradas percebem o ambiente:

  • Um botão de pressão, como um botão de "chamar atendimento" ou de "próxima página".
  • Um contato de porta ou janela, um interruptor reed ou uma chave de fim de curso.
  • Qualquer sensor com contato seco, como um fluxostato ou uma saída de relé em um detector de movimento.

As saídas agem sobre ele:

  • Um relé que libera uma fechadura elétrica, liga uma torre luminosa ou aciona um buzzer.
  • Um LED que ilumina um botão.

O aplicativo na tela faz o trabalho por meio de screenrig.device.gpio e conta ao seu agente o que aconteceu com emit, então "atendimento solicitado" aparece no registro de eventos do projeto. Seu agente cria o aplicativo, envia e o coloca na tela como qualquer outro. A página de hardware mostra o que mais um aplicativo pode acessar.

Quais Players têm GPIO

PlayerGPIOPull da entradaNível de repouso da saídaNúmeros de pino
Raspberry Pi 3, 4 e 5 (Player Linux)Sim, no header de 40 pinos. O Player encontra sozinho o chip do header"up", "down" ou "none"SimOs números BCM
Outras placas LinuxSim, com SCREENRIG_GPIO_CHIP"up", "down" ou "none"SimOs números de linha desse chip
Android e Amazon Signage StickOnde o dispositivo expõe um chip GPIO sysfs gravávelNão: adicione um resistorSimOs números de linha desse chip
BrightSignSim: pinos 0 a 7 no conector GPIO, ou um adaptador USB para GPIO da BrightSignPull-ups integradosSimPinos 0 a 7 e as faixas na seção BrightSign
macOS, Windows, o app web do Player, Samsung Smart Signage (Tizen), LG webOS SignageNãoNãoNãoNão

A flag vai para o controlador da página, ou para o aplicativo que está sozinho na página. Um aplicativo vê capabilities["device.gpio"] como true somente em um Player e em um dispositivo que tenham GPIO, então uma mesma versão também roda em uma tela sem ele.

Configure o Player

Raspberry Pi

Um Raspberry Pi não precisa de configuração. O Player Linux abre sozinho o chip do header de um Pi 3, 4 ou 5, e um pino é o seu número BCM. O usuário do Player precisa de acesso a /dev/gpiochip*. No Raspberry Pi OS, o usuário padrão pertence ao grupo gpio, que concede esse acesso. Uma instalação --kiosk adiciona sua conta apenas aos grupos video e i2c, então dê o grupo gpio a uma conta --kiosk-user diferente e reinicie o Player:

sudo usermod -aG gpio KIOSK_USER

Outras placas Linux

Em outra placa, indique o chip que traz as linhas com SCREENRIG_GPIO_CHIP, no ambiente de inicialização do Player:

SCREENRIG_GPIO_CHIP=/dev/gpiochip4

Para uma instalação --kiosk, adicione-o ao serviço com sudo systemctl edit screenrig-player-kiosk.service:

[Service]
Environment=SCREENRIG_GPIO_CHIP=/dev/gpiochip4

Um pino é então um número de linha desse chip. O usuário do Player precisa de acesso ao arquivo de dispositivo do chip.

Android

O Android tem GPIO quando o dispositivo expõe um chip GPIO sysfs gravável, como uma placa de digital signage ou uma imagem personalizada. Um pino é o número global de linha do chip. Uma TV box padrão não tem esse chip, e o aplicativo vê device.gpio como false. O Player mantém uma linha somente enquanto o aplicativo a usa. O Android não consegue definir o pull de uma entrada: ligue um resistor, como em Ligue um botão.

Escolha um pino

pin é um número inteiro de 0 a 255: o número da linha do chip. Em um Raspberry Pi, é o número BCM, o número GPIO que a documentação do Pi nomeia, e não a posição do pino no header. GPIO17 é o pino físico 11. Linhas comuns:

Número BCM (o pin)Pino físicoNota
1711Uma boa primeira linha
2713
2215
2316
2418
2522
529
631
1232
1333
1636
2637
2038
2140
2 e 33 e 5Linhas I2C com pull-ups fixos; deixe-as para o I2C
14 e 158 e 10As linhas do console serial
0 e 127 e 28Reservados para a identificação de HAT

O terra são os pinos físicos 6, 9, 14, 20, 25, 30, 34 e 39, e 3.3 V são os pinos 1 e 17. A documentação do Raspberry Pi lista o header inteiro. Uma linha que outro programa já mantém rejeita com pin_busy, e uma linha que o chip não tem rejeita com pin_not_found.

Ligue um botão

Ligue um botão de pressão entre uma linha GPIO e o terra, e ative o pull-up dessa linha. A linha lê alto até o botão ser pressionado, e um pressionamento a puxa para o terra, então um pressionamento lê baixo.

 GPIO17 (pin 11) -----+
                      |
                   [ button ]
                      |
 GND (pin 9) ---------+

Em um Raspberry Pi ou outra placa Linux, peça o pull-up ao Player com pull: "up":

window.screenrig.device.gpio.onChange(17, handlePress, { pull: "up" });

pull: "down" serve para um botão ligado a 3.3 V, que lê nível alto quando pressionado. "none" é o padrão: o Player não define polarização, então uma entrada sem nada conectado flutua e um botão sem resistor lê mudanças aleatórias.

O Android não define pull, então adicione um resistor de cerca de 10 kΩ da linha a 3.3 V (um pull-up) para um botão ligado ao terra. Um BrightSign tem pull-ups integrados nas entradas, e um botão ligado ao terra funciona como está.

Pedir "up" ou "down" em um Player que não consegue defini-lo não interrompe o manipulador: o SDK monitora a linha sem pull e registra uma entrada warn com o código gpio_pull_unsupported.

Acione um relé

Acione um relé por meio de uma placa de relé, e nunca diretamente de um pino. Um pino fornece alguns miliampères a 3.3 V, o que não consegue acionar a bobina de um relé, uma fechadura elétrica, uma torre luminosa nem um buzzer, e o pico de tensão de uma bobina pode danificar a placa. Uma placa de relé traz o transistor e a proteção da bobina.

 5V (pin 2) -------------- VCC |
 GND (pin 6) ------------- GND | relay board
 GPIO27 (pin 13) --------- IN1 |
                               |  COM ---- supply for the load
                               |  NO  ---- the load (door strike, light, buzzer)

Alimente a carga com a fonte própria dela, por meio dos contatos do relé. Escolha uma placa cuja entrada seja acionada com 3.3 V.

const sr = window.screenrig;
await sr.device.gpio.write(27, true);   // relay on
await sr.device.gpio.write(27, false);  // relay off

A maioria das placas energiza em nível alto. Muitas placas baratas são ativas em nível baixo: o relé energiza quando a entrada é puxada para baixo. Passe idle: true para uma placa ativa em nível baixo, de modo que uma página que sai libere o relé como desligado. Veja Nível de repouso.

await sr.device.gpio.write(27, false, { idle: true }); // active-low board: relay on
await sr.device.gpio.write(27, true, { idle: true });  // relay off

Uma saída em um BrightSign é 3.3 V por 100 Ω, então um BrightSign aciona uma placa de relé da mesma forma.

Somente 3.3 V

Toda linha GPIO usa lógica de 3.3 V. Os pinos de um Raspberry Pi não toleram 5 V, e 5 V em um pino pode danificar a placa. Conecte apenas contatos secos: um botão, um interruptor ou uma saída de relé que não carrega tensão própria. Um sensor com saída de 5 V, 12 V, 24 V ou tensão da rede elétrica precisa de um conversor de nível, um optoacoplador ou um relé entre ele e o pino.

Debounce

Um contato mecânico faz repique: por alguns milissegundos, um pressionamento oscila entre alto e baixo. O Player filtra o repique de contato, então o manipulador recebe um pressionamento como uma mudança e a liberação como mais uma. Uma linha no Linux ou no Raspberry Pi ignora mudanças que se estabilizam em cerca de 20 ms. Nenhum código seu é necessário, e um pulso mais curto que isso não é um uso para a entrada GPIO.

Monitorar uma linha

onChange(pin, handler, options) monitora uma linha. O manipulador recebe o nível como booleano, true para alto. A primeira chamada traz o nível que a linha tem quando o Player começa a monitorar, e cada chamada seguinte é uma mudança. A chamada retorna uma função que interrompe o monitoramento.

const stop = window.screenrig.device.gpio.onChange(17, function (high) {
  doorOpen = high;
}, { pull: "up" });

No máximo 16 linhas são monitoradas ao mesmo tempo, e uma 17ª lança invalid_request. Dois manipuladores em uma linha compartilham o pull dela: um segundo manipulador com pull diferente lança invalid_request imediatamente.

Nível de repouso

write(pin, value, options) aceita a opção idle, o nível para o qual o Player leva a linha quando a página a libera. O padrão é baixo. A página libera uma linha quando sai da tela, quando seu contexto termina e quando chama screenrig.destroy(). O Player então libera a linha. A gravação mais recente para um pino define seu nível de repouso.

É por isso que um relé não permanece energizado depois que a página sai. Defina idle como o nível que significa "desligado" para a sua placa: baixo na maioria das placas, alto em uma placa ativa em nível baixo.

Quando a página sai

O que uma página mantém termina com a página. Quando ela sai da tela, suas entradas param e toda saída vai para o nível de repouso e é liberada. Quando o Player para ou o dispositivo perde energia, as linhas vão junto. Planeje a carga considerando isso: escolha uma fechadura elétrica que trave ou destrave da forma que o prédio precisa quando falta energia.

Limites e erros

  • Um pino é um número inteiro de 0 a 255.
  • No máximo 16 linhas são monitoradas ao mesmo tempo.
  • write rejeita com invalid_request um pin, value ou idle inválido, com pin_not_found uma linha que o chip não tem, com pin_busy uma linha que outro processo mantém e com gpio_unavailable quando o Player não consegue abrir nenhum chip GPIO.
  • onChange lança invalid_request para uma 17ª linha ou um pull conflitante. Um monitoramento recusado é registrado em log, e o manipulador nunca é executado.
  • Uma chamada verifica inert, not_supported e capability_denied antes de enviar qualquer coisa. A referência do SDK lista a ordem. Um write com idle rejeita com not_supported em um Player que não consegue defini-lo.

Exemplo: chamar atendimento

Um botão no GPIO17, ligado ao terra, avisa seu agente de que um cliente quer ajuda, e um LED ou relé de buzzer no GPIO27 responde por cinco segundos. A primeira leitura é o nível que a linha já tem, então o manipulador age somente em uma mudança de alto para baixo.

const sr = window.screenrig;

function active() {
  return sr.readyState === "active";
}

async function start() {
  if (!sr) return;
  await sr.waitUntilActive();
  await sr.ready();
  if (!sr.supports("device.gpio") || !sr.capabilities["device.gpio"]) return;

  let wasHigh = null;
  sr.device.gpio.onChange(17, function (high) {
    const pressed = wasHigh === true && high === false;
    wasHigh = high;
    if (!pressed || !active()) return;
    sr.emit("service.requested");
    document.getElementById("message").hidden = false;
    sr.device.gpio.write(27, true).catch(function () {});
    setTimeout(function () {
      document.getElementById("message").hidden = true;
      if (active()) sr.device.gpio.write(27, false).catch(function () {});
    }, 5000);
  }, { pull: "up" });
}
start();

Quando a página sai da tela, a linha 27 é liberada em seu nível de repouso, baixo a menos que você passe idle, então um botão pressionado logo antes de a página sair não deixa o relé ligado.

Seu agente lê cada pressionamento no registro de eventos:

screenrig events list --type application.event --screen-id scr_SCREEN

Exemplo: entrada de porta aberta

Um interruptor reed no GPIO17, ligado ao terra, fecha quando a porta está fechada, então a linha lê baixo com a porta fechada e alto com ela aberta. A página mostra um aviso enquanto a porta está aberta e avisa seu agente.

const sr = window.screenrig;
const notice = document.getElementById("door-notice");

function show(open) {
  notice.hidden = !open;
  document.body.classList.toggle("door-open", open);
}

async function start() {
  show(false);
  if (!sr) return;
  await sr.waitUntilActive();
  await sr.ready();
  if (!sr.supports("device.gpio") || !sr.capabilities["device.gpio"]) return;
  sr.device.gpio.onChange(17, function (high) {
    show(high);
    if (sr.readyState === "active") sr.emit(high ? "door.opened" : "door.closed");
  }, { pull: "up" });
}
start();

BrightSign

Um player BrightSign executa a mesma API. Os pinos 0 a 7 são as linhas do conector GPIO, o conector dos modelos XT, XD e HD (um soquete DA-15); o pino 0 é a linha 0 do conector e o pino 7 a sua linha 7. Suas entradas têm pull-ups fixos, então pull não é oferecido e um botão ligado ao terra funciona como está. idle funciona como em todo Player. As saídas são 3.3 V por 100 Ω: acione um relé por meio de uma placa de relé.

Um BrightSign acrescenta mais dois bancos de linhas por USB:

PinosO que são
0 a 7O conector GPIO
8 a 39Expansores GPIO USB, 8 pinos cada, até 4: os pinos 8 a 15 são o primeiro expansor, 16 a 23 o segundo, e assim por diante
100 a 110Uma placa de botões BP200 ou BP900, número 0: o pino 100+k é o botão k como entrada, e o LED dele como saída
120 a 130, 140 a 150 e 160 a 170Placas de botões 1, 2 e 3, da mesma forma

Uma gravação no pino 100+k acende o LED do botão k, e um monitoramento no pino 100+k recebe o botão. Uma placa ou um expansor que não está conectado faz seus pinos rejeitarem com pin_not_found.

Experimente no app dev

screenrig app dev simula o GPIO. O ambiente de teste mostra um interruptor de chip GPIO e três linhas simuladas: 17 (baixa), 27 (alta) e 22, que outro processo mantém e por isso responde pin_busy. Os exemplos acima usam 17 e 27. Clique no nível de uma linha para alterá-lo, e seu aplicativo recebe a mudança quando monitora a linha. Uma gravação do aplicativo move a linha, e o painel mostra o nível de repouso que ela definiu. O ambiente de teste aceita pull e idle, então uma versão roda ali antes de chegar a uma tela. Desenvolver localmente descreve os controles.

Referência

Perguntas

Uma tela pode acionar um relé?
Sim, por meio de uma placa de relé. Um aplicativo define uma linha como alta ou baixa, e a placa aciona a fechadura elétrica, a torre luminosa ou o buzzer. Nunca acione um relé diretamente de um pino.
Um botão precisa de um resistor?
Em um Raspberry Pi ou outra placa Linux, não: peça o pull-up e ligue o botão ao terra. No Android, adicione um resistor de cerca de 10 kΩ a 3.3 V. Um BrightSign tem pull-ups integrados.
Qual número devo passar para um pino?
Em um Raspberry Pi, o número BCM: GPIO17 é 17 e fica no pino físico 11. Em outra placa, o número de linha do chip GPIO dela. Em um BrightSign, as faixas de pinos na seção BrightSign.
O que acontece com um relé quando a página muda?
O Player leva a linha ao seu nível de repouso, baixo a menos que o aplicativo tenha escolhido outro, e a libera. Escolha alto para uma placa de relé ativa em nível baixo, de modo que o relé fique desligado.
O aplicativo precisa ficar em execução o tempo todo?
O aplicativo escuta enquanto sua página está na tela. Quando a página sai, as entradas param e as saídas vão para o nível de repouso.
Quanto custa?
O screenRIG é gratuito. A placa, o botão e o relé são custo seu.