Controle a raspberry pi pelo Discord

Controle a Raspberry pi pelo Discord Deixe um comentário

Introdução

Neste post vamos utilizar o aplicativo de comunicação e mensagens Discord para controlar uma Raspberry Pi de forma remota, para isso vamos desenvolver um pequeno sistema de monitoramento residencial.

A Raspberry irá continuamente monitorar sensores e, ao detectar alguma anomalia, enviará uma mensagem ao usuário, que poderá então solicitar uma foto do local, ou ativar um alarme.

Sistema de automação residencial: controlando a raspberry pi pelo Discord

 

Material necessário

Montagem do circuito

Controle a raspberry pi pelo Discord

A Raspberry deve ser configurada com o sistema operacional Raspberry OS, o post Primeiros passos com Raspberry Pi e Linux contém o passo a passo para instalar o sistema operacional no cartão SD.

Vamos utilizar um mini sensor de presença PIR, este sensor possui uma interface bem simples, alta sensibilidade e confiabilidade, além de poder ser integrado facilmente com a Raspberry Pi através do módulo gpiozero. O sensor possui três fios, sendo dois de alimentação e um de sinal, pelo qual o sensor transmite um sinal em alto toda vez que um objeto for detectado, veja o post Acendendo uma lâmpada com sensor de presença para mais informações e exemplo de como utilizá-lo (o modelo utilizado é um pouco diferente, porém o princípio é o mesmo).

Desenvolvimento

O que é o Discord?

O discord é um aplicativo de comunicação através de mensagens instantâneas e Voz sobre IP (VoIP) projetado especificamente para ser um mecanismo de comunicação entre jogadores em jogos on-line, no entanto o aplicativo se tornou extremamente popular e não é incomum seu uso fora da comunidade de jogadores.

Controle a raspberry pi pelo Discord

Uma vez que jogos eletrônicos podem requerer uma grande quantidade de recursos do computador, o discord foi projetado para ter um impacto mínimo na performance, quando comparado a outras soluções.

Um dos usos mais comuns do discord é proporcionar um chat de texto para membros de determinadas comunidades, onde os integrantes podem conversar entre si e receber informações dos moderadores da comunidade. Algumas comunidades podem possuir centenas de membros, o que tornaria a moderação um desafio, felizmente o aplicativo permite automatizar tais tarefas através de bots.

Construir um bot no discord é bem simples e por ter uma grande comunidade existem diversas implementações de sua API pública em diversas linguagens de programação. Bots podem executar as mais variadas tarefas, desde as mais úteis como moderar comentários e banir membros desrespeitosos às mais esdrúxulas e divertidas como tocar Bad Apple.

A única coisa necessária para configurar um bot online é um cliente que deve estar sempre disponível para receber e processar os comandos do discord, uma raspberry pi pode facilmente assumir esse papel, podemos ainda tomar proveito das GPIOs da raspberry para nos comunicarmos com hardware externo através do discord.

Configurando o Discord

Criar uma conta no Discord

Para utilizar o discord é necessário criar uma conta, acesse o site da plataforma, ou baixe os aplicativos para celular ou PC, e clique em registre-se.

Controle a raspberry pi pelo Discord

Siga os passos mostrados na tela, ao término você terá acesso à interface do discord, onde poderá criar ou se juntar a servidores nos quais poderá se comunicar com os demais membros através de mensagens de texto, voz e até chamadas de vídeo.

Criando um Aplicativo

Para termos acesso à API do discord é necessário cadastrarmos nosso aplicativo, para isso basta acessar o portal de desenvolvedores do discord e logar com a mesma conta criada anteriormente. Após acessar com sua conta você verá a página Applications, listando todos os aplicativos que você criou e cadastrou no Discord, clique em New Application para criar um novo.

Controle a Raspberry pi pelo Discord

Dê um nome para sua aplicação e clique em Create, a página de configuração do aplicativo será aberta, aqui você pode alterar as configurações da sua aplicação bem como renomeá-la. Você também encontrará as informações necessárias para que sua aplicação acesse a API do Discord, como pretendemos interagir com o Discord através de um User Bot podemos ignorar essas informações e passar para sua criação.

Criando um bot

No menu lateral à esquerda clique na guia Bot e em seguida no botão Add Bot, um user bot será automaticamente criado com o mesmo nome que sua aplicação.

Controle a Raspberry pi pelo Discord

Na guia Bot é possível alterar as configurações do User Bot, renomeá-lo, alterar a imagem e obter o seu Token de acesso, o qual será necessário para que a Raspberry possa se conectar ao Discord. O token deve ser mantido em segredo pois qualquer um que tiver o token terá total controle sobre o bot.

Controle a Raspberry pi pelo Discord

Por fim precisamos adicionar o bot recém criado a um servidor, você pode adicioná-lo a qualquer servidor que tenha permissão de gerenciamento. Para criar um novo servidor basta clicar no botão de mais no menu lateral esquerdo na página principal do discord.

Criando um bot

Para adicionar o bot no servidor retorne à página de configuração da aplicação, clique em OAuth2 e na seção scope selecione a opção bot, uma nova seção Bot Permissions surgirá, selecione somente as permissões que seu bot necessita e tenha cautela ao atribuir qualquer função administrativa a um bot, desta forma caso o bot seja comprometido não haverão grandes complicações.

Para esse projeto serão necessárias apenas permissões de texto, veja na imagem abaixo as permissões utilizadas:

permissões de texto discord

Na seção “scopes” você verá um link, copie e cole-o no seu navegador, certifique-se de estar logado na sua conta do Discord. Uma janela de confirmação aparecerá perguntando a qual servidor deseja adicionar o User Bot, selecione o servidor e clique em autorizar, agora seu bot tem acesso a este servidor.

Todas as configurações necessárias no discord já foram feitas, podemos passar para as configurações da Raspberry PI.

Preparando o ambiente na Raspberry Pi

Agora que criamos um aplicativo e um bot no discord, vamos configurar a raspberry para se comunicar com o discord através do bot.

Com o sistema operacional instalado e conectado à internet, certifique-se que a raspberry e os pacotes estão atualizados inserindo os seguintes comandos no terminal:

sudo apt-get update
sudo apt-get upgrade

Vamos desenvolver nossa aplicação em Python, o ambiente de desenvolvimento em Python já vem pré-configurado no Raspberry OS, precisamos apenas baixar alguns pacotes adicionais para interagir com a câmera e a API do discord.

Felizmente já existe um módulo Python criado especificamente para comunicação com a API do discord, o discord.py. Este módulo pode ser obtido através do gerenciador de pacotes Python pip, basta inserir o seguinte comando em um terminal:

sudo pip3 install discord.py

Além deste módulo python vamos precisar do pacote fswebcam para tirar fotos através da webcam USB. Digite o seguinte comando em um terminal:

sudo apt-get install fswebcam

Com isso temos tudo configurado para desenvolvermos nosso Bot.

Código do Bot

Criando um comando simples

Antes de construir um sistema complexo, vamos criar um bot (aqui chamado de BerryBot) simples que apenas responde a comandos do usuário a fim de nos familiarizarmos com o discord.py. Crie um arquivo (este pode ser tanto na raspberry quanto no PC convencional) e cole o seguinte código:

#!/usr/bin/env python3
import discord
from discord.ext import commands


# Insira o Token do bot
TOKEN = “INSERIR-TOKEN-AQUI”


berrybot = commands.Bot(command_prefix=’$’)


@berrybot.command()
async def ping(ctx):
    “””Reply with a Pong”””
    await ctx.send(“pong”)


@berrybot.command()
async def hello(ctx):
    “””Nice to meet you! ; )“””
    await ctx.send(f“Olá {ctx.message.author.mention}, eu sou o {ctx.me.mention}!”)


berrybot.run(TOKEN)

Substitua o valor da variável TOKEN para o token do seu bot, obtido no painel de configurações.

Criando um bot

Salve o arquivo como discord-test.py, se estiver utilizando um sistema Linux, não se esqueça de dar permissão de execução ao arquivo utilizando o comando:

chmod u+x

Execute o Script e entre no servidor em que o bot se encontra, você verá que o User Bot aparece como online. Teste enviar as mensagens “$ping” e “$hello”, imediatamente o bot lhe enviará uma resposta. Também é possível utilizar o comando “$help” para listar todos os comandos aceitos pelo bot.

criando um bot

Neste script simples estamos utilizando a classe Bot do módulo discord, esta classe foi especificamente construída para facilitar a criação de bots. O parâmetro command_prefix, definido ao instanciar a classe, específica como todos os comandos devem iniciar, o user bot ignora qualquer mensagem que não inicie com command_prefix.

Após isso, criamos duas funções assíncronas decoradas, o decorador indica que as funções são callbacks de comandos e serão executadas toda vez que um usuário enviar uma mensagem contendo o comando específico. Por padrão o nome da função é utilizado como comando, ou seja, uma função nomeada foo é invocada quando um usuário enviar um comando $foo, no entanto é possível especificar um comando diferente passando um argumento nomeado name para o decorador.

@bot.command(name=”foo”)
async def __other_name_function(ctx):
    await ctx.send(“bar”)

Toda função de comando deve ser assíncrona (usar a keyword async) e receber como primeiro parâmetro o contexto da mensagem, o qual é utilizado para enviar a resposta. Note o uso da keyword await ao enviar a mensagem, ela é necessária pois send é uma função assíncrona.

Sistema de Monitoramento residencial

Agora que nosso bot simples está funcionando e somos capazes de interagir com ele pelo discord, vamos aumentar um pouco a complexidade do código e desenvolver um sistema de monitoramento residencial.

O código fonte deste projeto pode ser encontrado no meu github, não convém explicar aqui o código linha a linha pois a maior parte consiste nas funções que já foram explicadas no exemplo simplificado. O código do projeto está dividido nos arquivos:

  • __main__.py – Script de inicialização. Deve ser executado para iniciar o bot, responsável por carregar e configurar todos os demais;
  • core.py – Contém funções e variáveis que são utilizadas por todos os demais scripts;
  • commands.py – Contém todos os comandos reconhecidos pelo bot;
  • tasks.py – Contém todas as tarefas, funções assíncronas que são executadas continuamente enquanto o programa estiver sendo executado;
  • configuration.py – Classe de configuração, responsável por ler o arquivo de configuração e providenciar os valores para os demais scripts;
  • config.json – Arquivo de configuração, contém todas as configurações do projeto, incluindo o valor do TOKEN do discord.

Estamos particularmente interessados em três arquivos: commands.py, tasks.py e config.json, estes três permitem a customização do Berry Bot. Vamos analisar cada um deles, começando pelo commands.py.

import os
import core
import pathlib
import discord
import gpiozero


@core.BerryBot.command()
async def ping(ctx):
    """Reply with a pong"""
    await ctx.send("pong")


@core.BerryBot.command()
async def hello(ctx):
    """Nice to meet you!"""
    await ctx.send(f"Olá {ctx.message.author.mention}, eu sou o {ctx.me.name}!")


buzzer = gpiozero.Buzzer(core.Config.alarm_gpio)
@core.BerryBot.command()
async def alarm(ctx, on_time:float=1, off_time:float=0.6, n:int=5):
    """Sets the alarm! Scare the Intruder!"""
    buzzer.beep(on_time, off_time, n)
    await ctx.send(f"Alarme acionado")


image_counter = 0
@core.BerryBot.command()
async def picture(ctx, frames:int = 5):
    """Let-me see their face! Let-me see now!"""
    global image_counter
    frames = int(frames) if frames > 0 else 1
    picture_name = os.path.join(
        os.path.join(os.path.join(pathlib.Path(__file__).parent.absolute(), core.Config.image_path)),
        f"frame_{image_counter}.jpg"
    )
    try:
        await ctx.send("Aguarde por favor ...")
        os.system(f"fswebcam -F {frames} {picture_name}")
        with open(picture_name, 'rb') as f:
            df = discord.File(f)
            await ctx.send(file=df)
        image_counter = (image_counter + 1) % core.Config.image_buffer_size
    except Exception as e:
        await ctx.send(f"Error! {e}")

Neste arquivo estão todos os comandos aceitos pelo BerryBot. Além dos dois comandos de teste: hello e ping, outros dois comandos estão presentes no script:

Alarm – aciona um alarme composto por um buzzer. Este comando aceita alguns parâmetros que podem ser especificados após a mensagem de comando, separados por espaços:

$alarm <time_on : float> <time_off : float> <n : int >

Os parâmetros especificam por quanto tempo o alarme deve permanecer ligado, por quanto tempo deve permanecer desligado e por quantas vezes o ciclo deve se repetir. Se os parâmetros não forem especificados no discord, os valores padrões serão utilizados.

Picture – tira uma foto do ambiente através da webcam USB. Esse comando utiliza o pacote fswebcam, as fotos são salvas dentro de uma pasta especificada e enviadas para o discord, para evitar problemas com armazenamento o número máximo de fotos salvas é limitado, quando atingido as mais antigas vão ser excluídas e sobrescritas com as novas. Este comando também aceita um parâmetro, especificando o número de frames (fotos) que serão tiradas para compor a única imagem final, quanto maior o número de frames maior a qualidade da foto, porém leva mais tempo para processar e caso haja um objeto se movendo em frente a câmera a imagem poderá ficar borrada.

Vamos passar para o próximo script e analisar task.py:

import core
import discord
import asyncio
import gpiozero
import functools
import time


alert_channel = None
sensor = gpiozero.MotionSensor(core.Config.sensor_gpio)
last_alert_time = 0
def sensor_when_motion_callback():
    async def send_alert():
        “””
        Envia mensagem de alerta para um canal específico do discord,
        precisa ser assíncrona para poder chamar a corrotina send
        ”””
        global alert_channel
        global last_alert_time
        if alert_channel is None:
            if not core.BerryBot.is_ready():
                await core.BerryBot.wait_until_ready()
            alert_channel = core.BerryBot.get_channel(core.Config.alert_channel)
        current_time = time.time()
        if (current_time - last_alert_time) > core.Config.sensor_time_interval:
            last_alert_time = current_time
            await alert_channel.send("Alerta! Intruso detectado!")
    def _call_on_future():
        asyncio.ensure_future(send_alert())
    core.Loop.call_soon_threadsafe(_call_on_future)


# Motion Sensor Callback
sensor.when_motion = sensor_when_motion_callback

Este arquivo especifica tarefas que devem rodar na raspberry e notificar o discord quando necessário, neste caso, enviar uma alerta toda vez que o sensor de presença detectar algum movimento.

Utilizamos a classe MotionSensor incluída em gpiozero para a leitura do sensor, essa classe foi especificamente construída para lidar com um sensor PIR e inclui todas as funcionalidades necessárias.

A classe MotionSensor permite configurar uma função de callback que será chamada toda vez que o sensor detectar presença ou movimento, a leitura e processamento das informações do sensor, bem como a execução do callback, é feito em uma thread secundária, de forma a não bloquear a execução do código principal. Infelizmente não podemos simplesmente atribuir uma função que envie uma mensagem para o discord, pois o módulo gpiozero é construído de forma multi-thread síncrona e o módulo discord.py de forma single-thread assíncrono.

Note que a função de callback define algumas funções internas e as utiliza nas funções call_soon_threadsafe e ensure_future, ambas do módulo asyncio. Tais funções, respectivamente, garantem que a thread secundária do gpiozero não interfira com a thread principal (que trata os comandos do discord) e permite que o código síncrono de MotionSensor possa chamar as funções assíncronas do discord. As mensagens de alerta são enviadas para um canal específico do discord, definido no arquivo de configuração.

Por fim vamos analisar o arquivo de configuração, trata-se de um simples arquivo JSON com alguns valores importantes definidos.

{
    "name": "BerryBot",
    "version": [1, 0, 0],
    "token": "<INSIRA SEU TOKEN AQUI>",
    "alert_channel": <ID DO CANAL>,
    "command_prefix": "$",
    "sensor_gpio": 20,
    "alarm_gpio":21,
    "sensor_time_interval": 300,
    "image_buffer_size": 10,
    "image_path": "./frames"
}

Você pode adicionar chaves e valores nesse arquivo que podem ser acessados pelo código através do objeto Config definido em core.py, as chaves que são utilizados pelo código atual, bem como suas funções estão listadas à seguir:

  • name – Nome do programa, utilizado apenas para exibição ao início da execução;
  • version – Versão do programa, utilizado apenas para exibição ao início da execução;
  • token – Token de acesso do user bot do discord;
  • alert_channel – Id do canal onde devem ser enviadas às mensagens de alerta;
  • command_prefix – Prefixo dos comandos do discord;
  • sensor_gpio – Número da GPIO associada ao sensor PIR;
  • alarm_gpio – Número da GPIO associada ao alarme (buzzer);
  • sensor_time_interval – Tempo mínimo em segundos que deve decorrente entre cada detecção do sensor de presença para que um alerta seja enviado. Evita que vários alertas sejam enviados em sequência caso um objeto fique entrando e saindo da frente do sensor;
  • image_buffer_size – Quantidade máxima de imagens que serão salvas localmente, após atingir esse limite as mais antigas serão deletadas e sobrescritas por novas;
  • image_path – Caminho da pasta onde serão salvas as imagens.

O id do canal pode ser obtido no painel principal do discord, ao criar uma aplicação sua conta deve ter automaticamente ativado o modo de desenvolvedor, a opção pode ser ativada ou desativada em configurações, aparência, avançado, modo de desenvolvedor e permite visualizar algumas informações úteis para a construção de bots utilizando a API do discord. Com o modo de desenvolvedor ativo selecione o servidor em que seu bot foi adicionado, clique com o direito em um dos canais de texto disponíveis e clique em copiar ID, cole o valor no arquivo de configurações. As mensagens de alerta serão automaticamente enviadas para este canal.

Encontrar o id do canal

Projeto em Funcionamento

Vídeo: https://youtu.be/-5-V6V3o6Ss

Note que a imagem exibida pela webcam é de baixa qualidade e apresenta um tom esverdeado, isso se deve a uma combinação de limitações da webcam e do software. Lembre-se que o comando picture aceita um parâmetro que especifica o número de frames a serem utilizados para compor a imagem, a fim de providenciar uma resposta mais rápida configurei o valor padrão para cinco frames, aumentando este valor é possível capturar imagens de maior qualidade a um custo de um maior tempo de processamento e exigência de que os objetos fotografados permanecem imóveis durante o processo, caso contrário a imagem sai borrada.

Veja na imagem abaixo um exemplo de foto tirada com 50 frames (10 vezes maior que o padrão), note como a qualidade da imagem aumenta significativamente. É possível perceber que a imagem permanece desfocada, no entanto isto é uma limitação física da câmera cujo foco deve ser ajustado manualmente (a câmera utilizada não suporta foco automático).

exemplo de foto tirada com 50 frames

Conclusão

Neste post vimos como é possível controlar a Raspberry Pi através do Discord em um projeto simples. Para projetos mais complexos é possível desenvolver sistemas utilizando recursos avançados do discord e da Raspberry. Dê uma olhada no projeto remoteDiscordShell de Enrique Moran, trata-se de um shell remoto para Linux através de mensagens do discord, incluindo login de usuário e restrições de acesso root.

Gostou do post Controle a Raspberry Pi pelo Discord? Não esqueça de deixar seu comentário logo abaixo.

Faça seu comentário

Acesse sua conta e participe