Manual

do

Maker

.

com

Acione relé e abra portas com MQTT e Raspberry

Acione relé e abra portas com MQTT e Raspberry

Nessa segunda fase, vou exibir o acendimento da lâmpada e a abertura da porta, além do ligamento e desligamento do monitor; tudo por MQTT. Além do código (em Python) para automatizar as tarefas, também coloco exemplos para debug com o client Mosquitto para publicar e inscrever-se em um tópico.

O código disponibilizado é apenas para a prova de conceito, implemente um tratamento melhor se pretende utilizá-lo de forma permanente.

MQTT não é gráfico

Mas antes de seguirmos, precisamos esclarecer algumas coisas a respeito de MQTT, porque estou percebendo que a visão geral da galera quando se fala nesse protocolo de IoT é que lhes vem logo à mente gráficos mostrando as informações. Por isso, acho ideal deixar claro que MQTT é o acrônimo de Message Queue Telemetry Transport utilizado na comunicação M2M (machine-to-machine). Utilizar uma interface de "contemplação" é algo adicional. Uma vez que o protocolo trafega mensagens realmente curtas (e dependendo do nível de QoS selecionado, insignificante), aplicar uma interface supervisória é algo bastante simples e acredite, todo o processamento significativo estará nesse sistema supervisório.  Isso significa que se você quer entregar ao usuário um monitoramento, o ideal é que primeiramente não seja em PHP (serei odiado por isso, mas tentarei explicar). É minha opinião exclusiva e totalmente pessoal e justifico-a com uma simples observação; o PHP é interpretado no servidor. Pense que você tem um broker (que não necessariamente oferece um sistema supervisório) e as mensagens trafegando por MQTT ficam em torno de 50 bytes. Não faz muito sentido dedicar processamento pra um serviço de background que não gera processamento. Por isso, uma das opções (e que não é a melhor) é utilizar o plugin do Google para gerar gráficos. Outra opção seria qualquer coisa que processe do lado cliente. Enfim, eu vou implementar aqui em casa do jeitinho que eu falei pra não fazer - com PHP. Mas essa parte da configuração fica mais pra frente, para o próximo post. Agora vamos à configuração da estrutura.

Passo 1 - Instalar a parte física na porta de casa

Um amigo meu pensou nisso aqui quando falei em destrancar as portas da casa:

tranca_feia-300x247.webp

Jamais nessa vida eu usaria tal horrorosidade na porta da sala. Se o fizesse, contrataria um porteiro, porque isso tem cara de tranca de portaria de prédio.

Outra coisa que fez ele ficar resistente foi em relação às modificações necessárias na estrutura física; logo ele pensou em um sensor daqueles monstrinhos brancos que um vai na porta e o outro no batente. Enfim, pra resumir, o que eu utilizei foi esse:

trava_de_porta-225x300.webp

Essa trava é acionada por pulsos de 12v. Dediquei uma fonte a essa trava, assim como cada elemento da composição de minha estrutura tem sua própria fonte. E por uma razão; eu não possuo uma fonte de computador. Uma fonte de computador escondida embaixo do balcão suporta até 20A, alimentaria tudo e ainda sobraria um monte, além de que dela posso tirar 12v e 5v diretamente. Para menos que 5v ou valores intermediários, basta utilizar um Regulador De Tensão LM2596 e tudo fica lindo.

A vida de um maker...

Infelizmente esse "Fecho Elétrico Soprano 12v Para Batente" não veio com o furo do batente. Isto é, eu tive que ajustar o batente para encaixá-lo; foi a madeira do batente, depois o concreto do batente, depois os detalhes mais fáceis. Uma composição das etapas:

composite.webp

Após muita sujeira, bolhas nas mãos e suor saindo até pelas unhas, consegui aquele resultado do lado da maçaneta quebrada. Acidentes acontecem.

Parece tudo muito simples e muito fácil, mas o problema não está exclusivamente relacionado ao trabalho manual. Consideremos que estou dentro de casa; por qual razão eu preciso de usuário e senha para sair de casa? De dentro para fora não preciso disso, além de que isso fragilizaria a segurança na necessidade de escape (a chave resolveria, bastando destravar até o final). Por essa razão, instalarei um botão para gerar a interrupção manual de dentro de casa.

Ainda falando da tranca, ela tem "memória". Isto é, ela destrava e a qualquer momento você pode sair (ou entrar). Ao abrir a porta a trava já voltará ao estado anterior, não havendo necessidade de sequer passar a chave (caso você desabilite o retorno do trinco pela chave.

Para garantir que não sej possível destrancar a porta virando a chave até recuar a trava da maçaneta, um furo e um pino já é o suficiente. Para monitorar se a porta está aberta ou fechada, utilizarei um imã de neodímio na porta e um reed switch no batente; o imã já está instalado na porta, faltando o reed switch nos encaixes que já fiz no batente. Para saber se a porta está trancada com chave tem várias opções; um furo na trava para imã de neodímio e então um reed switch dentro do batente, ou então um LED receptor e um LED emisso IR, etc.

Com isso, estou liberto de voltar pra casa para verificar se realmente fechei a porta. Para complementar essa parte, um indicador visual também não é nada mal para quem está dentro de casa. Por isso, colocarei um LED verde e um LED azul dentro do batente para gerar status visual (no próximo post, relacionado exclusivamente às firulas).

Em relação à lâmpada, não há segredos, uma vez que o teste já foi feito com o LED, bastou reproduzir. Mas deixo minha recomendação:

Se você for menor de idade, mora com os pais, a casa é alugada, tem vizinhos arredores que podem morrer com suas experiências, não goza de plenas faculdades mentais, é dislexo (portanto interpreta mal), é inseguro, não sabe a diferença de tensão e corrente, programa em Python (igual eu), PHP (parecido comigo), só faz as coisas via Ctrl+Chups - NÃO FAÇA NENHUM DESSES PROCEDIMENTOS, APENAS LEIA E DESFRUTE DA LEITURA. Ainda que excessão a todos os mencionados (e não mencionados), TODO O PROCEDIMENTO É POR SUA CONTA E RISCO. Se você implodir seu bairro, matar o gato, derrubar o transformador do poste ou outra coisa qualquer, não me faça responsável por isso.

Dito isso, sigamos.

 Como são feitos os acionamentos

Em se tratando de um sistema operacional Linux, não importa que ele seja embarcado. Realmente a diferença está exclusivamente na arquitetura, ademais, a interação com  sistema é tão permissiva quanto em um desktop. Por isso, você pode (e deve) utilizar-se dos mais vastos recursos oferecidos pelo sistema. Não há desenvolvimento mais ágil do que automação de tarefas com shell script - um recurso nativo do sistema operacional, mas atípico para programadores e hobistas. Imagine então que para publicar e inscrever-se a um tópico, utilizaremos a linha de comando do Linux, de modo que não será necessário programação. Não é fantástico? Seria, mas o client mosquitto_sub dessa versão disponível para o RPi não ajudou, mais adiante explico.

MQTT e Raspberry: Publish com mosquitto_sub

Uma coisa que já estou fazendo é monitorar a temperatura do Raspberry Pi pela linha de comando, enviando os valores a ele próprio (que é o broker) utilizando o aplicativo de linha de comando mosquitto_pub:

mosquitto_pub -h 192.168.1.2 -u dobitaobyte -P senhaSecreta -p 1883 -t rpi/temperature -m "$(echo ` vcgencmd measure_temp|sed -re 's/.*([[:digit:]]{2,})/\1/; s/\.[[:digit:]].*//'`)" -q 1

Veja que em apenas um comando coletei o valor da temperatura, peguei apenas a parte inteira dela, conectei ao broker e enviei o resultado ao tópico. Muito prático, não? Hum? Aquele monte de caracteres? Ah!

É muito bom pra você saber shell script, o que lhe dará uma agilidade sem precedentes. Esse tipo de comando acima eu não estudo, do jeito que estou digitando esse texto eu digito o comando acima - e não estou escrevendo isso pra dizer que sou "bão"! Apenas quero dizer que isso se torna parte dos seus dedos após acostumar-se. Para não deixá-lo desanimado, vou explicar brevemente alguns conceitos.

Você pode executar mais de um comando por vez no shell do Linux. A saída (ou resultado) de um comando serve como entrada para outro comando. O separador deles é o pipe (simbolo "|"). Na linha acima, executei o comando mosquitto_pub passando como parâmetro para o tópico temperature o valor da temperatura do processador do RPi. Para não precisa pegar o valor e guardar em uma variável, fiz o processamento em fluxo. Para fazê-lo, há dois modos; executar o comando dentro de crases (assim: ``) ou executá-lo dentro de um subshell assim: $(comando). Em ambos os casos, não importará o que está dentro, mas o resultado da execução do que está dentro desses executadores de comandos. Se ainda está complexo o entendimento, não se preocupe, iniciarei uma série de treinamento em shell script em breve.

Subscribe com mosquitto_sub

Esse é de dar dó. No desktop tradicional você tem a opção da flag "-C" que lhe permite pegar uma entrada e sair do subscriber. Com isso, você consegue criar shell scripts para fazer o M2M. Só que no RPi a versão que precisa ser instalada do Mosquitto não tem essa flag no subscriber e nem criando dispositivo FIFO eu consegui desconectar do subscriber para interagir com o resultado. Por isso, o subscriber só será útil para debug. Não deixa de ser útil por isso - e mais - se alguém (incluindo Julio Cesar Neves) tiver uma solução para despregar do mosquitto_sub, adiciono aqui e crio um manipulador shell.

mosquitto_sub -h 192.168.1.2 -u dobitaobyte -P senhaSecreta -p 1883 -t /mcu/LED_status -q 1

Usei o tópico /mcu/LED_status para fazer o teste. Não me importa o tópico MCU por enquanto, é apenas para ver funcionando; esse tópico está em uso pelo Wemos, que você encontra aí em posts anteriores.

Mosquitto-python e Paho

Na documentação do Mosquitto você encontra menos de 10 linhas de informação. Com certeza esse post que vos escrevo lhes será útil.

Instalar python-paho

Para isso, siga os passos:

sudo su
apt-get install python-pip
pip install paho-mqtt

Minha próxima dica (e acredite, preciosa) é a instalação do programa bpython. Esse programa te dá recursos de auto-complete para as bibliotecas importadas e pode ser fundamental na ausência de uma boa documentação.

sudo apt-get install bpython

Vou fazer um video mostrando sua utilização juntamente com 'vim' e 'screen' para vocês sentirem o poder dessas ferramentas de console.

Esse é um exemplo que achei na documentação, só adicionei usuário e senha e troquei as credenciais do broker e tópico.

#!/usr/bin/env python
# # -*- coding: UTF-8 -*-
# Author: J. F. Mitre <http://jfmitre.com>
# Created: Tue 16 Feb 2016 22:12:31 BRST
# Last Update: Tue 16 Feb 2016 22:12:31 BRST
# File: <name>
# Notes: 
import paho.mqtt.client as mqtt
import time,os
# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))

    # Subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed.
    #client.subscribe("$SYS/#")
    client.subscribe("rpi/#")

# This function will parse and execute the correct command
def parse_result(message):
   msg = str(message.payload)
   topic_msg = str(message.topic)
   if topic_msg == "rpi/sala/luz_bancada":
      f = open("/sys/class/gpio/gpio21/value","w")
      if msg == "1":
         #TODO: criar constantes
         try:
            f.write("0")
            client.publish("rpi/sala/status/luz_bancada","On")
         except:
               client.publish("rpi/sala/status/luz_bancada","Erro")
      elif msg == "0":
         try:
            f.write("1")
            client.publish("rpi/sala/status/luz_bancada","Off")
         except:
            client.publish("rpi/sala/status/luz_bancada","Erro")
      f.close()
   elif topic_msg == "rpi/sala/porta":
      if msg == "1":
         #TODO: criar constantes
         try:
            for i in range(2):
              f = open("/sys/class/gpio/gpio20/value","w")
              time.sleep(0.1)
              f.write("0")
              f.close()
              time.sleep(0.1)
              f = open("/sys/class/gpio/gpio20/value","w")
              f.write("1")
              f.close()

            client.publish("rpi/sala/status/porta","Opened")
         except:
               client.publish("rpi/sala/status/porta","Erro")

   elif topic_msg == "rpi/monitor":
         if msg == "on":
            os.system("display on")
            client.publish("rpi/status/monitor","On")
         else:
            os.system("display off")
            client.publish("rpi/status/monitor","Off")
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    parse_result(msg)
    print(msg.topic+" "+str(msg.payload))

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.username_pw_set("dobitaobyte","senhaSecreta")
client.connect("ns1", 1883, 60)

# Blocking call that processes network traffic, dispatches callbacks and
# handles reconnecting.
# Other loop*() functions are available that give a threaded interface and a
# manual interface.
client.loop_forever()

Pra finalizar a segunda parte desse artigo...

Contemple agora o video do funcionamento da abertura de porta e acendimento da lâmpada da bancada pelo smartphone utilizando o MyMQTT (que é um app para debug, como já citei anteriormente). Esses são os requisitos funcionais de sistema. No próximo post relacionado mostrarei a implementação dos requisitos não-funcionais, que são os status dos eventos ainda não tratados como o da porta aberta e porta destrancada. Além disso, LEDs de status embutidos no batente e uma página de gerenciamento com gráficos bonitinhos serão implementados e assim você já poderá ter um produto finalizado.

Vídeo de apresentação

Inscreva-se no nosso canal Manual do Maker Brasil no YouTube.

Próximo post a caminho!

Nome do Autor

Djames Suhanko

Autor do blog "Do bit Ao Byte / Manual do Maker".

Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.