FVM – Como é que o Raspberry Pi pode acender uma luz
... à distância?
Por Projecto MagicKey do Instituto Politécnico da Guarda para o PPLWARE.COM
Temos mostrado muitas funcionalidades desta nova pequena maravilha que é o Raspberry Pi. Hoje mostramos mais uma aplicação deste mini PC, numa solução que foi desenvolvida pela Magickey para todos os leitores do Pplware.
A ideia inicial deste projecto foi adicionar algo mais, ao simples desenvolvimento mostrado no artigo já antes publicado no Pplware – Como podemos acender uma luz com o Raspberry Pi. Hoje vamos mostrar como podem evoluir o projecto, podendo a luz ser controlada à distância. O objectivo é ligar e desligar a lâmpada a partir de um smartphone Android e houve também a necessidade de decidir a tecnologia de comunicação a utilizar e também o protocolo de comunicação.
A arquitectura utilizada para este projecto deverá ser a seguinte:
Como tecnologia de comunicação, a escolha recaiu no uso comunicação socket's UDP, permitindo assim uma comunicação mais flexível uma vez que o overhead é menor. De referir que cada equipamento deverá possuir uma ligação a Internet.
É claro que para que seja possível existir comunicação socket entre dois equipamentos ambos têm que conhecer os seus IP's e portos de comunicação. No entanto, tento o Android como o Raspberry poderão estar ligados em redes que usem o mecanismo NAT e dai os seus IP's poderão see dinâmicos. Para este projecto, optou-se por utilizar um servidor central que gere a ligação entre ambos, à semelhança do que é feito com alguns serviços web, como por exemplo chat's.
O servidor central que deverá possuir IP publico estático, correr uma aplicação socket's UDP servidor que está constantemente à escuta. O Raspberry, para se dar a conhecer ao servidor, envia a letra “R”; o servidor ao receber guarda o endereço e porto de origem de comunicação ficando assim com a identificação do Raspberry.
Quando recebe uma comunicação de um qualquer IP com “l” ou “d” reencaminha a mensagem para o Raspberry.
O Raspaberry ao receber liga ou desliga a lâmpada através da electrónica já conhecida.
Código para correr no Raspberry PI
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/ioctl.h> #include <setjmp.h> #include <wiringpi.h> int main() { int sock, n, nr; char word[1]="R"; char recebi[110]="A"; char envio[1]="d"; socklen_t length; int count=0; int teste; int var=0; struct sockaddr_in server, from; sock = socket(AF_INET, SOCK_DGRAM, 0); if(sock <0) { printf("nao criou o cliente"); } memset(&server, 0, sizeof(struct sockaddr_in)); server.sin_family =AF_INET; server.sin_port = htons(8888); server.sin_addr.s_addr = inet_addr("***.***.***.***"); //ip do servidor length = sizeof(struct sockaddr_in); //scanf("%d",&nr); //nr = htonl(nr); if (wiringPiSetup () == -1) { pinMode (7, OUTPUT); } else { pinMode (7, OUTPUT); } n = sendto(sock, &word, sizeof(word),0,(const struct sockaddr *)&server, length); if(n <0) { printf("nao enviou"); } while(1) { int erro=ioctl(sock,FIONREAD,&count); printf("\ntenho por ler %d",count); if(count>0) { printf("recebi"); teste=sizeof(server); n = recvfrom(sock,recebi,count,0,(struct sockaddr *)&server,&teste); //sscanf(recebi,"%d",&teste); //printf("%d",teste); if(strcmp(recebi,"l") ==0){ printf("ligar"); digitalWrite(7,1); }else if(strcmp(recebi,"d") ==0){ printf("desligar"); digitalWrite(7,0); } }else{ /*printf("nao recebi"); n = sendto(sock, &envio, sizeof(envio),0,(const struct sockaddr *)&server, length); if(n <0) { printf("nao enviou"); }*/ var++; printf("%d",var); if(var==100) { var=0; n = sendto(sock, &word, sizeof(word),0,(const struct sockaddr *)&server, length); if(n <0) { printf("nao enviou"); } } sleep(2); } } return 0; } |
Código para correr no Servidor
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Net.Sockets; using System.Threading; using System.Net; namespace tcp_server { public partial class Form1 : Form { public Form1() { InitializeComponent(); } Server se; static bool ligado = false; private void button1_Click(object sender, EventArgs e) { se = new Server(); timer1.Start(); button1.Enabled = false; } string mensagem = ""; private void timer1_Tick(object sender, EventArgs e) { label1.Text = se.gettreadcont().ToString(); label2.Text = se.gettreadabertas().ToString(); if (checkBox1.Checked) { mensagem = se.getmens(); if (mensagem != "") listBox1.Items.Insert(0, mensagem + " h:" + DateTime.Now.Minute + ":" + DateTime.Now.Second); } } private void button2_Click(object sender, EventArgs e) { fechar = true; this.Close(); } bool fechar = false; private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (e.CloseReason == System.Windows.Forms.CloseReason.UserClosing && !fechar) { e.Cancel = true; } else { Environment.Exit(0); } } private void listBox1_SelectedIndexChanged(object sender, EventArgs e) { } private void Form1_Load(object sender, EventArgs e) { button1_Click(sender, e); } } class Server { public static int treadcont = 0; static int treadaberta = 0; public static string mensagem = ""; public static string smensagem = ""; List<string> imei= new List<string>(); List<string> lat = new List<string>(); List<string> log = new List<string>(); static List<string> velo = new List<string>(); private UdpClient server; private IPEndPoint receivePoint; private IPEndPoint receivePointRASP; static bool ligado = false; public int gettreadcont() { return treadcont; } public string getmens() { string aux = mensagem; mensagem = ""; return aux; } public string getsmens() { string aux = smensagem; smensagem = ""; return aux; } public int gettreadabertas() { return treadaberta; } public Server() { Thread serv = new Thread(new ThreadStart(ListenForClients)); serv.Start(); Thread servr = new Thread(new ThreadStart(ListenForClientsr)); servr.Start(); } private void ListenForClients() { server = new UdpClient(8888); receivePoint = new IPEndPoint(IPAddress.Any, 0); byte[] message = null; while (true) { ASCIIEncoding encoder = new ASCIIEncoding(); try { //blocks until a client sends a message message = server.Receive(ref receivePoint); string s = "l"; server.Send(encoder.GetBytes(s), 1); } catch { //a socket error has occured } //the client has disconnected from the server string recebida = encoder.GetString(message); mensagem = recebida; if (recebida.Contains("R")) { receivePointRASP = receivePoint; } else { try { server.Send(message, message.Length, receivePointRASP); server.Send(message, message.Length, receivePoint); } catch { } } } } private void ListenForClientsr() { server = new UdpClient(8889); receivePoint = new IPEndPoint(IPAddress.Any, 8889); byte[] message = null; while (true) { try { //blocks until a client sends a message message = server.Receive(ref receivePoint); } catch { //a socket error has occured } //the client has disconnected from the server ASCIIEncoding encoder = new ASCIIEncoding(); string recebida = encoder.GetString(message); mensagem = recebida; if (mensagem == "d") { ligado = false; } else if (mensagem == "l") { ligado = true; } } } } } </string></string></string></string></string></string></string></string> |
Para quem estiver interessado a colocar este projecto em prática, disponibilizamos o código fonte para o servidor, Raspberry PI e Android. Alguma duvida ou questão, deixem em comentário que teremos todo o gosto em colaborar.
Download: Código para PI, Servidor e Android aqui
Este artigo tem mais de um ano
No código para correr no Raspberry PI.
Qual é o objetivo deste IF? o código executado é sempre o mesmo.
if (wiringPiSetup () == -1)
{
pinMode (7, OUTPUT);
}
else
{
pinMode (7, OUTPUT);
}
Pois é, esse IF não está a fazer ai rigorosamente nada.
Obfuscation Level: Beginner! xD
Esclareçam-me uma dúvida. A utilização do servidor neste caso era “dispensável” correto? Este projeto poderia ser desenvolvido sem recurso ao servidor
Boas Zee, sim. O servidor apenas serve para que haja um ponto central, conhecido, entre equipamentos.
Isto pode ser usado como domótica de uma casa para as luzes?
Sim, com uns melhoramentos e alterações, não para uma lâmpada mas para um leque enorme de funcionalidades típicas da domótica. Persianas, portões, lâmpadas, etc
De notar que o que aqui foi descrito é apenas a parte de software. Ainda falta a parte da electrónica da lâmpada. As lâmpadas das nossas casas usam 220V AC e o RPi tem saídas de 3,3V DC. Logo o Rpi não pode acender directamente a lâmpada.
Para isso será necessário um transístor e um relé para a acender e isolar o Rpi dos 220V.
Essa parte está nesta notícia algo similar
https://pplware.sapo.pt/hardware/como-que-o-raspberry-pi-pode-acender-uma-luz/
Porque não o recurso a um serviço de dns dinâmico do tipo no-ip ou ddns para suprimir o servidor que para além de aumentar a complexidade, aumenta também os gastos/consumos e desperdiça energia?
Ou até porque não instalar um servidor ssh no raspberry e permitir assim a comunicação segura dos dados e aumentando o leque de possibilidades do projecto?
Sim., também se poderia usar. É so dar asas à imaginação e evoluir 🙂
Ola Zé,
de facto essa é uma opção valida, e de certo mais acertada para a construção de soluções deste tipo.
Visto que a equipa tinha ao seu dispor todos os equipamentos que utilizamos optarmos por esta implementação.
O objectivo foi desde inicio mostrar como é fácil construir um sistema muito básico para controlo de um dispositivo eléctrico à distancia. E penso que este foi cumprido.
Boas…
Porque é que o Servidor aumenta os gastos de energia?
Na realidade aumenta, mas de uma forma muito reduzida…aqui para este caso…pelo que percebi(não sei qual a linguagem…pelo horror e por algumas coisas eu diria que a linguagem do servidor deve ser Java Based…talvez C# da M$?), no enatnto o importante é que utiliza mecanismos bloqueantes, o que faz com que os processos não estejam sempre a correr…alias eles são colocados numa fila de wait até receberem via um interrupt ordem para correr codigo…por exemplo quando uma nova sms chega…
Por esse motivo quando se fala em gastos de energia, presumo que te refiras ao facto de haver um servidor(hardware) extra para o efeito, e não servidor software(o verdadeiro servidor).
Essa solução pode ser muito prática de facto para um equipamento…
mas agora imagina que eu estou a gerir uma rede com 1000 equipamentos…Um Servidor pode dar imenso geito…imagina que fazes recolha de dados de x em x tempo, por exemplo.
Um servidor vai concentrar toda a info num so local.
cmps
Seria possível disponibilizarem no zip o código da app android? O código mesmo e não o apk já compilado.
Thanks
webiopi a funcionar e acedo diretamente ao raspberry para comutar os dispositivos usando o browser
Gostaria de saber se podem mostrar um projecto em Pi para comandar através de frequências (wireless ou ondas de radio), emitir e receber sinais, tipo apagar um led ou aceder, mas tudo isso a distancia ex: 300 m, sem fios pelo meio?
tipo ter um emissor de frequências e um receptor para isso ?
dá para fazer no PI e como ?
obrigado?
skysurf
Olá,
o que nós pedes é bastante simples de implementar.
Basta usar dois XBee devidamente configurados e tens uma porta serie Wireless a funcionar, daí para a frente é apenas trabalhares com a tradicional comunicação serie entre dispositivos.
Quem sabe o próximo post não poderá ser o que pedes…
Vejam aqui um projeto semelhante para publicarem as vossas criações 😉
http://livebots.cc/
Há alguém com coragem para alterar o “C” para Python?
Como podemos saber as livrarias necessárias?
Está porreiro este tutorial, mas não há maneira de ter só o RPI ligado e com o android enviar comando para ligar ou desligar? Sem o uso de um outro pc a fazer de servidor??
Podiam também colocar o código em phyton 🙂
https://www.youtube.com/watch?v=4Q9wVS6mOwk
onde eu abro depois de baixar ???
Boa tarde, estou a fazer um trabalho onde me foi proposto desenvolver um novo produto contendo o Raspberry Pi. É um trabalho teórico, visto que a prática nem se quer faz parte da minha área. Contudo o que gostava de ‘desenvolver’ era um controladora de gastos, isto é, através do Rapberry Pi tornar possível a qualquer pessoa saber, diariamente, quanto gastamos, a nível monetário, de eletricidade e de água. Teoricamente o produto dividia-se em duas partes, a Raspberry Pi que se encontra ligada aos contadores da água e da luz, e uma aplicação para o telemóvel que faz a transformação das quantidades consumidas em despesas monetárias. Não sei até que ponto seria possível, mas se for, gostaria de saber as especificações mais técnicas para a montagem de tudo isto.
preciso mesmo de ajuda : /