Pplware

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 
#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.


Download: Código para PI, Servidor e Android aqui

Exit mobile version