… à 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
#include
#include
#include
#include <sys/ioctl.h>
#include
#include
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 imei= new List();
List lat = new List();
List log = new List();
static List velo = new List();
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;
}
}
}
}
}
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.