Introduction: Smart Piscina Com IoT - Ionic, Dweet E DragonBoard
Introdução
Apresento aqui uma solução para monitoramento e tratamento de piscinas de maneira remota, que poderia ser usado tanto pelo proprietário de um imóvel, como por algum piscineiro que poderia verificar remotamente diversas piscinas as quais ele atende.
O hardware utilizado é baseado na placa DragonBoard da Qualcom e na placa Linker Mezanine da 96boards. Também serão utilizados sensores da Arrow para a placa Linker Mezanine.
Esta não é uma implementação final! Mas sim um desenvolvimento para mostrar como realizar a programação do Hardware, a comunicação com um serviço repositório na nuvem e a criação de um app para acesso e controle do sistema. As funções criadas são:
-Controle do PH da Piscina
-Acionamento da Bomba e monitoramento
-Monitoramento do nível do reservatório de produto para tratamento
Arquitetura IoT
A automação e o controle do tratamento da piscina são realizados pela Dragonboard, com interface do usuário via app Web. Para que isto seja possível, é utilizada a arquitetura demonstrada na imagem, e consiste em:
- Os dados são lidos e processados pela Dragonboard
- A DragonBoard escreve em um repositório na Web, neste caso o Dweet.io
- O Dweet.io disponibiliza as informações lidas para que sejam disponíveis para outras aplicações
- Um aplicativo Web desenvolvido no Ionic e Acessa os dados do Dweet.io e apresenta em uma interface HTML para o usuário
Step 1: Configuração Do Hardware
Como dito, foi utilizada a DragonBoard 410c para realizar a automação e controle local da piscina. Junto com a Dragonboard foi instalada um shield da 96boards chamado Linker Mezanine, que facilita o acesso aos IOs da DragonBoard. Este shield tb possui dois conversores A/D para leitura de dados analógicos. Nas imagens existe a configuração utilizada para conexão dos IOs deste exemplo.
- Foi considerado o uso de um PHmetro que forneça uma saída proporcional de 0 a 5V para que seja compatível com a entrada do A/D. Caso seja utilizado um com sinal maior, será necessário um divisor resistivo para compatibilizar o sinal com a entrada
- No exemplo, ao invés de um PHmetro foi utilizado um potênciometro para simulação do sinal
- Para simular o acionamento da bomba foi utilizado um led, que em um projeto real poderia ser um acoplador ótico acionando um TRIAC ou relé
- O sensor de rotação da bomba foi simulado com um sensor de toque. Em uma aplicação real poderia ser um sensor no eixo da bomba ou um contado auxiliar do contator que aciona a bomba. Neste caso, em caso de defeito da bomba ou queda do disjuntor, seria possível verificar que a bomba foi acionada e não está girando
- O sensor para nível do reservatório é um do tipo "tilt" que deverá ser instalado em uma bóia
- Por fim, a doseagem de produto é feita por uma eletroválvula acionada por um relé
Step 2: Preparação Da DragonBoard
Atualização da Placa e instalação das bibliotecas p/ 96boards
A placa DragonBoard vem de fábrica com uma distribuiçaõ Linux chamada Linaro, ela é suficiente em recursos para executar esta aplicação, bastando atualizar a placa e realizar a instalação das bibliotecas da 96boards para interface com a Linker Mezanine.
Uma vez que estamos trabalhando em Linux, podemos acessar o Terminal para realizar os comandos de atualização e instalação de bibliotecas:
Os seguintes comandos realizam a atualização da placa:
sudo apt-get update
sudo apt-get upgrade sudo apt-get dist-upgrade
Para trabalhar com o Python, também realize a instalação de um editor de textos e do interpretador
sudo apt-get install gedit
sudo apt-get install python-pip
Na sequeência serão instaladas as Bibliotecas necessárias. Os comandos devem ser apresentados na ordem a seguir e são críticos para a instalação correta:
sudo apt-get install build-essential autoconf
automake libtool-bin pkg-config python-dev sudo reboot
LIBSOC (Acesso a Linker Mezanine)
git clone https://github.com/jackmitch/
libsoc.git cd libsoc sudo autoreconf -i sudo ./configure --enable-python=2 --enableboard= dragonboard410c --with-board-configs sudo make sudo make install sudo ldconfig /usr/local/lib sudo reboot
96boards:
git clone https://github.
com/96boards/96BoardsGPIO.git
cd 96BoardsGPIO/
sudo ./autogen.sh sudo ./configure sudo make sudo make install sudo ldconfig
Quase no fim... mas aproveitamos para instalar tb a biblioteca para acesso a parte analógica da Linker Mezanine:
git clone https://github.com/doceme/pyspidev.git cd py-spidev sudo python setup.py install sudo ldconfig sudo reboot
É importante lebrar que na LIBSOC estão as referências de endereçamento da Linker Mezanine, e serve de referência caso precise acessar diretamente um endereço de IO
sudo gedit /usr/local/etc/libsoc.conf
Step 3: Criação Do Objeto No Dweet.io
Como o próprio slogan diz, o dweet.io funciona como um Twitter para IoT, onde as coisas podem enviar e receber dados pela internet de maneira facilitada
Uma característica importante é que o Dweet não necessita de uma autenticação complexa para acessar os dados, o que o torna interessante para início dos testes com IoT.
Para criar o objeto no Dweet basta seguir os seguintes passos:
- Acessar o Dweet.io e clicar em "Play"
- Na guia POST crie um nom para o obejto no campo "thing"
- No campo "content" adicione os dados que serão lidos e enviados. Os dados devem estar no formato "json"
- Clique em "Try it out!" e observe o resultado em "Response Body"
- Caso queira confirmar o uncionamento da "coisa", vá até o campo "Get Lattest Dweet", insira o nome do obje criado e clique em "Try it out" para verificar a resposta do Dweet.
Para esta aplicação foi criado o objeto "smart_piscina" que tem o seguinte conteúdo:
{
"status_tratamento": 0,
"ligadesliga_bomba": 0,
"status_bomba":0,
"status_reservatorio":0,
"PH_setpoint":6,
"PH_valor": 4
}Nele estão todos os dados necessários para comunicação entre a DragonBoard e a aplicação Web.
É importante ressaltar que o nome do objeto deve ser alterado no Dweet e no código fonte das aplicações para evitar que outros dispositivos acessem simultaneamente a coisa gerando resultados indesejados
Step 4: Programação Em Python
Lógica de Funcionamento
O software de Controle da Piscina foi desenvolvido em Python, que é uma linguagem simples e interpretada, ou seja não necessita de compiladores para obter a execução da aplicação.
As funções realizadas pelo software piscina_final.py, que roda na DragonBoard são as seguintes:
- Controla o PH, monitorando o valor medido na piscina e comparando com o "Setpoint" definido pelo usuário no Web app. A correção será feita dosando produto através do acionamento da eletroválvula.
- O acionamento da eletroválvula é temporizado, ou seja, uma certa quantidade de produto é dosada e a lógica aguarda um determinado período para realizar uma nova dosagem
- O controle só é realizado se a bomba da piscina estiver em funcionamento e se o nível do tanque de produto para dosagem estiver ok!
- Quando o PH atinge um valor superior ao desejado, a dosagem para automaticamente
- Controla a bomba, ligando e desligando a mesma através do Web app, conforme solicitação do usuário
- Monitora e informa ao usuário o nível do reservatório do produto de Dosagem
- Informa anomalia na bomba, caso seja ligada e não rode.
Antes de apresentar o código, devemos realizar alguns ajustes na Dragonboard para que ela se comunique adequadamente com o Dweet.io
Componentes adicionais
Instalar a biblioteca REQUESTS para realizar funções de POST e GET em HTTP
sudo pip install requests
Copiar o arquivo dweet.py para a mesma pasta onde está a aplicação smart_piscina.py
Código Fonte em Python
A seguir apresentamos o código por partes, nesta primeira são lidas as bibliotecas necessárias, configurados os IOs e realizada a leitura analógica do valor de PH.
import spidev
import time from dweet import Dweet from libsoc import gpio from gpio_96boards import GPIO
COMANDO_BBA = 36 #Comando Bomba NIVEL_PROD = 13 #Chave de nivel DOSAGEM_VVL = 115 #Valvula Dosagem BBA_LIGADA = 24 #Retorno de Bomba ligada GPIO_CS = 18 #Sensor PH (Analogico) pins = ( (GPIO_CS, 'out'),(COMANDO_BBA, 'out'),(DOSAGEM_VVL, 'out'),(NIVEL_PROD, 'in'),(BBA_LIGADA, 'in') )
dweet = Dweet()
spi = spidev.SpiDev() spi.open(0,0) spi.max_speed_hz=10000 spi.mode = 0b00 spi.bits_per_word = 8def readPH(gpio): gpio.digital_write(GPIO_CS, GPIO.HIGH) time.sleep(0.0002) gpio.digital_write(GPIO_CS, GPIO.LOW) r = spi.xfer2([0x01, 0x80, 0x00]) gpio.digital_write(GPIO_CS, GPIO.HIGH) adcout = (r[1] << 8) & 0b1100000000 adcout = adcout | (r[2] & 0xff) adcout = (adcout * 0.014) #converte para PH 0 a 14 return adcout
Na segunda parte, é realizada a leitura do Dweet e os dados armazenados em variáveis globais para as logicas do software:
def le_dweet(): #Le qual setpoint para tratamento
global ld_bomba, st_bomba, st_trat, st_res, PH_valor, PH_SP resposta = dweet.latest_dweet(name="smart_piscina") ld_bomba = resposta['with'][0]['content']['ligadesliga_bomba'] st_bomba = resposta['with'][0]['content']['status_bomba'] st_trat = resposta['with'][0]['content']['status_tratamento'] st_res = resposta['with'][0]['content']['status_reservatorio'] PH_valor = resposta['with'][0]['content']['PH_valor'] PH_SP = resposta['with'][0]['content']['PH_setpoint'] return ld_bomba, st_bomba, st_trat, st_res, PH_valor, PH_SP
A terceira parte é a função que realiza o tratamento da piscina, com a lógica para acionamento baseada no PH, nível do reservatório e bomba ligada. Note que as variáveis de monitoramento são as mesmas lidas pelo Dweet, desta forma conseguimos atualizar os valores na lógica para que despois sejam novamente enviados ao serviço.
def tratamento():
global st_trat, st_res, st_bomba st_res = gpio.digital_read(NIVEL_PROD) st_bomba = gpio.digital_read(BBA_LIGADA) if (PH_valor < PH_SP) and ( st_res == 1) and ( st_bomba == 1): gpio.digital_write(DOSAGEM_VVL, GPIO.HIGH) time.sleep(2) #tempo da dosagem do produto gpio.digital_write(DOSAGEM_VVL, GPIO.LOW) time.sleep(1) #espera entre dosagens st_trat = 1 print("TRATAMENTO lIGADO") else: gpio.digital_write(DOSAGEM_VVL, GPIO.LOW) st_trat = 0 print("TRATAMENTO DESlIGADO") return st_trat, st_res
A quarta e última parte é o looping de execução da lógica. A ordem onde as subrotinas são chamadas é importante para que os dados lidos pelo Dweet sejam atualizados e depois enviados para a correta visualização no Web app.
if __name__=='__main__':
with GPIO(pins) as gpio: while True: le_dweet() tratamento() PH_valor = round(readPH(gpio), 2) if ld_bomba == 1: gpio.digital_write(COMANDO_BBA, GPIO.HIGH) print("Bomba Ligada") else: gpio.digital_write(COMANDO_BBA, GPIO.LOW) print("Bomba Desligada") print("Valor do PH = %d" % PH_valor) print("Valor do SP PH = %d" % PH_SP) print("") dweet.dweet_by_name(name="smart_piscina", data={"ligadesliga_bomba":ld_bomba, "status_bomba":st_bomba, "status_tratamento":st_trat, "status_reservatorio":st_res, "PH_valor":PH_valor, "PH_setpoint":PH_SP}) time.sleep(10)
Attachments
Step 5: Desenvolvimento Do APP - Ambiente Hídrido
Plataforma híbrida Ionic
O aplicativo para controle da piscina será desenvolvido utilizando uma plataforma híbrida, ou seja, fazemos a abstração do hardware que o app será utilizado e desenvolvemos um projeto utilizando HTML, CSS e Javascript que posteriormente pode ser convertido em um app para uma plataforma específica como Android ou IOS.
Neste caso utilizamos o IONIC, que funciona baseado na plataforma Cordova, que permite visualizar e testar a aplicação através da renderização na mesma na tela de um Web Browser.
Para o Desenvolvimento do app, utilizaremos a linguagem HTML e Typescript. o IONIC também permite a utilização do framework Angular para trabalhar ocs componentes como Models e Controllers.
Instalação do Ambiente de Desenvolvimento
O desenvolvimento do app será realizado em um computador pessoal, e não na placa DragonBoard. Iniciaremos com a instalçaão do node.js, necessário apra o funcionamento do Ionic
Acessar o site https://nodejs.org/en/ e fazer o Download da última versão do node.js
Após concluída a instalação, o gerencador de pacotes NPM deve ter sido instalado durante a instalação do node.js. Ele permitirá realizar a instalação do Ionic.
No prompt de comando do Windows realize a instalação com os seguintes comandos:
npm install –g cordova ionic
npm install –g cordova
Para testar o ionic, o seguinte comando pode ser executado e se estiver tudo ok retornará a versão instalada:
ionic –v
Criação da aplicação no Ionic
Não, não tem uma interface gráfica bonita. Tem que criar o app utilizando a linha de comandos. Mas depois a facilidade de uso compensa.
Para criar uma nova aplicação, neste caso a smart_piscina, digitamos o seguinte comando:
ionic start smart_piscina blank
Será criada uma nova aplicação em branco que estará salva no diretório:
C:\Usuários\Nome do usuário\smart_piscina
Para testar o código:
cd smart_piscina
ionic serve
Será aberta uma tela no navegador padrão mostrando a aplicação em branco
Step 6: Desenvolvimento Do APP - Edição Da Aplicação
A edição da aplicação em branco gerada pelo Ionic será realizada no Visual Studio Code, aplicativo gratuito de programação desenvolvido pela Microsoft e que pode ser baixado no site: https://code.visualstudio.com/download
Os códigos alterados são apresentados a seguir, mas também estão disponíveis para download.
Interface
A interface com o usuário será editada no arquivo home.html. Note que as tags utilizadas são próprias do Ionic e contém alguns parâmetros inseridos utilizando os recursos do framework Angular. Os recursos do Angular são utilizados no botão de acionamento da bomba e na entrada do valor de Setpoint do PH. Não é possível apresentar o código aqui por uma limitação do Instructables, que apaga as tags. De qualquer forma está disponível no arquivo compactado para download.
Processamento
As fuções referentes a leitura e escrita de dados no Dweet e lógicas em geral para o correto funcionamento da interface estão no arquivo home.ts desenvolvido em Typescript, liguagem muito semelhante ao Javascript
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';//É preciso importar o provideer. import { DweetProvider } from '../../providers/dweet/dweet';
@Component({ selector: 'page-home', templateUrl: 'home.html' })
export class HomePage {
constructor(public navCtrl: NavController, private DweetProvider: DweetProvider) { }
//Declarações de Variáveis public respostaDweet: string=""; public status_tratamento: string="danger"; public st_trat = 0; public status_bomba: string="danger"; public st_bba = 0; public status_reservatorio: string="danger"; public st_res = 0; public locais = Array(); public PH_val = 0; public SP_PH = 0;
//Model do botão de ligar bomba public bomba_model = { checked: false, name: "Ligar Bomba" }
ionViewDidLoad () { //buscando os dados no Dweet e salvando nas variáies locais this.DweetProvider.getLastestDweet("smart_piscina").subscribe( data=>{ const response = (data as any); const objeto_retorno = JSON.parse(response._body); this.locais = objeto_retorno.with[0].content; this.bomba_model.checked = objeto_retorno.with[0].content.ligadesliga_bomba; this.st_bba = objeto_retorno.with[0].content.status_bomba; this.st_trat = objeto_retorno.with[0].content.status_tratamento; this.st_res = objeto_retorno.with[0].content.status_reservatorio; this.PH_val = objeto_retorno.with[0].content.PH_valor; this.SP_PH = objeto_retorno.with[0].content.PH_setpoint; console.log(this.locais); }, error => { console.log(error); } ) //Atualiza icones de Status this.status_bomba = ((this.st_bba == 1) ? "secondary" : "danger"); this.status_tratamento = ((this.st_trat == 1) ? "secondary" : "danger"); this.status_reservatorio = ((this.st_res == 1) ? "secondary" : "danger"); }
//Botão Atualizar update() { this.ionViewDidLoad(); }
//Liga Desliga Bomba liga_des_bomba(){ this.dweetPost() }
atualiza_sp(){ this.dweetPost() }
dweetPost(){ //Converte dados do botão de Boolean para inteiro const ld_bba = ((this.bomba_model.checked == true) ? 1 : 0);
//Envia dados para o Dweet.io const json_dweet = {"ligadesliga_bomba": ld_bba, "status_bomba": this.st_bba, "status_tratamento": this.st_trat, "status_reservatorio": this.st_res, "PH_valor": this.PH_val, "PH_setpoint": this.SP_PH}; this.DweetProvider.setDweet("smart_piscina",json_dweet).subscribe( data=>{ console.log(data); }, error=> { console.log(error); } ) } }
Dweet provider
É necessário criar um provider para realizar a comunicação HTTP com o Dweet. Isto é feito através do Ionic com o seguinte comando no prompt de comando:
ionic generate provider dweet
Neste momento é gerado o arquivo dweet.ts que deverá ter os comandos referentes a conexão com o Dweet e realização das funções de GET e POST. O código necessário é exibido a seguir:
import { Http } from '@angular/http';
import { Injectable } from '@angular/core'; import 'rxjs/add/operator/map';/* Generated class for the DweetProvider provider.
See https://angular.io/guide/dependency-injection for more info on providers and Angular DI. */ @Injectable() export class DweetProvider {
private baseUrl = "https://dweet.io:443/"
constructor(public http: Http) { console.log('Hello DweetProvider Provider'); }
//Método responsável por buscar as informações no Dweet. getLastestDweet(thing: string) { const url_get = this.baseUrl + "get/latest/dweet/for/" + thing; console.log(url_get); return this.http.get(url_get); }
//Método resposnsável por modificar os dados no Dweet. setDweet(thing, body) { return this.http.post(this.baseUrl + "dweet/for/"+ thing, body); }
}
Por fim, é necessário realizar uma modificação no arquivo app.module.ts para que carregue adequadamente os componentes HTTP para o funcionamento do Dweet Provider:
import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core'; import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular'; import { SplashScreen } from '@ionic-native/splash-screen'; import { StatusBar } from '@ionic-native/status-bar';import { HttpModule } from '@angular/http'; import { MyApp } from './app.component'; import { HomePage } from '../pages/home/home'; import { DweetProvider } from '../providers/dweet/dweet';
@NgModule({ declarations: [ MyApp, HomePage ], imports: [ BrowserModule, IonicModule.forRoot(MyApp), //Importar o modulo HTTP usado pelo Dweet. HttpModule ], bootstrap: [IonicApp], entryComponents: [ MyApp, HomePage ], providers: [ StatusBar, SplashScreen, {provide: ErrorHandler, useClass: IonicErrorHandler}, DweetProvider ] }) export class AppModule {}
Ufa!
Salve tudo e teste a aplicação através do comando:
ionic serve
Attachments
Step 7: Colocando Tudo Para Funcionar!!
1.Iniciando o Dweet:
No site Dweet.io, crie o objeto conform descrito no passo 3
2.Iniciando a aplicação na DragonBoard:
Abra o Terminal no Linaro, acesse a pasta onde está a aplicação smart_home.py e digite o comando:
sudo python smarthome.py
3.Iniciando a aplicação no Ionic:
Abra o prompt de comando, acesse a pasta onde está o aplicativo criado no Ionic e digite o comando
ionic serve


