Control de luces vía TCP/IP

 

Gonzalo Silva L. 2121026-9

Manuel P. Cohen Sch. 2121059-5

 

Resumen:

El sistema realizado tiene la finalidad de controlar luces remotamente o cualquier otro dispositivo conectado a la red eléctrica de 220Vrms. En otras palabras podemos controlar las luces, lavadora, etc. de nuestra casa desde cualquier parte del planeta mediante Internet. Para ello se necesitan solamente 2 computadores uno que haga de cliente y otro de servidor, éste último localizado en el lugar donde se encuentran los dispositivos a controlar.

 

Introducción:

 

Sería muy útil el tener la posibilidad de poder actuar sobre ciertos dispositivos a distancia como es el caso de luces u otros artefactos eléctricos. Complementando con los conocimientos adquiridos en el curso, se propuso la idea de utilizar la Internet como medio de comunicación entre el cliente y el actuador.

 

Para abordar el problema existen 2 objetivos que cumplir. El primero fue poder actuar sobre un switch electrónico, el cual conmuta 220 para así poder encender o apagar un dispositivo que no consuma más de 4[A] mediante una aplicación Java. El segundo objetivo fue enviar una palabra de control desde el cliente hacia el servidor con la finalidad de que el servidor tome alguna acción sobre el switch donde estaría conectado el dispositivo a controlar. A continuación se presenta un esquema que muestra la arquitectura del sistema:

 

 

En la figura se puede apreciar la conexión entre el cliente y el servidor. Además podemos ver que el switch es controlado por el bit 0 de la puerta paralela. El switch a su vez se encuentra en serie con la ampolleta y la fuente de alimentación.

 

Control de luces

 

Antes de entrar en el tema del software, comencemos por el pinout de la puerta paralela que se muestra a continuación:

 

 

Bastará con utilizar cualquier bit de data del puerto para obtener la señal de control para el switch. En nuestro caso nos quedamos con el bit 0

 

Para que este proyecto haya sido llevado a la realidad fue necesario estudiar como utilizar el puerto paralelo desde Java. Para ello fue necesaria la búsqueda de un archivo DLL que permitiera ser invocado desde java mediante el JNI. De esta manera nuestro código puede interactuar con las rutinas creadas en lenguaje nativo C que tienen directa comunicación con el periférico requerido. El archivo DLL llamado jnpout32pkg.dll fue necesario guardarlo en la ruta C:\Windows\System32. Una vez ya hecho esto, es posible desde Java invocar al paquete jnpout32 donde se encuentran los métodos nativos contenidos dentro del archivo DLL. Destacamos que nosotros no hemos estudiado el código fuente del archivo DLL, sólo estudiamos la implementación con Java. Puede descargar el código fuente del archivo jnpout32pkg.dll acá.

 

El programa del servidor consta de 3 archivos .java.

 

         ioPort.java

        Se declaran los métodos nativos de jnpout32.dll

         pPort.java

        Declaración clase pPort que invoca a métodos de la clase ioPort

         LightServer.java

        Programa principal

 

Para entender mejor la idea, miremos el siguiente diagrama que muestra como van relacionadas las clases en el programa del servidor:

 

Diagrama_clases.jpg                                              

Clase ioPort:

En la clase ioPort se declaran los métodos nativos encargados del control de la puerta paralela. Los métodos declarados son los siguientes:

 

public native void Out32(short PortAddress, short data);

Escribe una palabra de 1 Byte (data) a la dirección del puerto LPT dada por PortAddress

 

public native short Inp32(short PortAddress);

Lee una palabra de 1 Byte desde la dirección del puerto LPT dada por PortAddress. No utilizada en nuestro caso

 

Para poder cargar el paquete se utiliza la instrucción:

 

static { System.loadLibrary("jnpout32pkg");}

 

Clase pPort:

El constructor de esta clase crea el objeto pp de tipo ioPort, setea la dirección del puerto de impresora que en este caso es 0x378 y por último setea todos los bits en 0. Tal como se aprecia a continuación:

 

public pPort()

   {

              pp = new ioPort();

              portAddress = (short)0x378;     // Direccion LPT

              setAllDataBits((short)0);       // Se setean incialmente en 0 todos los bits

              currentVal = 0x00;

   }

 

Los demás métodos se declaran como wrappers de los que se declaran en la clase ioPort, por ejemplo:

 

  public void output(short port, short value)

   {

              pp.Out32(port, value);

   }

 

Aquí se aprecia que el método output (short port, short value) llama al método Out32 del objeto

pp que es instancia de la clase ioPort.

 

 

Hay más métodos dentro de la clase pPort, que no fueron utilizados para este proyecto. De todas maneras los listamos y describimos a continuación:

OBS: port y value son argumentos mientras que portAddress se fija en el constructor

 

 

Cabe destacar que una vez que sea crea el objeto pp, el constructor setea todos los bits del puerto en 0x00 mediante el método setAllDataBits

 

LightServer:

 

Esta sección del programa contiene el método main y crea el socket necesario para entregar el servicio al cliente.

A continuación se muestra el código encargado de generar el socket, interpretar el stream de llegada como string de texto y crear el objeto ltp como una instancia de la clase pPort

 

         // establish server socket

         ServerSocket s = new ServerSocket(8189);

 

         // wait for client connection

         Socket incoming = s.accept( );

         BufferedReader in = new BufferedReader

            (new InputStreamReader(incoming.getInputStream()));

         PrintWriter out = new PrintWriter

            (incoming.getOutputStream(), true /* autoFlush */);

 

         out.println( "Hello! Enter BYE to exit." );

         lpt = new pPort();

 

En la siguiente sección del programa se puede apreciar el valor que toma la variable datum para un mensaje dado del cliente. Para el caso ON datum=0xFF ->se prende el switch, y para el caso OFF datum=0x00 ->se apaga el switch. En el caso que reciba desde el cliente el mensaje BYE, se sale del bucle while y se cierra la conexión.

 

  // echo client input

         boolean done = false;

         while (!done)

         { 

            String line = in.readLine();

            if (line == null) done = true;

            else

            { 

               System.out.println("Echo: " + line);

              

               if (line.trim().equals("ON")){

                  datum=0xFF;

                  do_write();

               }

              

               if (line.trim().equals("OFF")){

                  datum=0x00;

                  do_write();

               }

              

               if (line.trim().equals("BYE"))

                  done = true;

            }

         }

         incoming.close();

      }

      catch (Exception e)

      { 

         e.printStackTrace();

      }

   }

 

Por último, tenemos el método do_write() que simplemente muestra el dato recibido desde el cliente y llama al método output del objeto lpt para escribir en la puerta

 

   static void do_write()

     {

          // Notify the console

          System.out.println("Write to Port: " + Integer.toHexString(Addr) +

                              " with data = " +  Integer.toHexString(datum));

          //Write to the port

          lpt.output(Addr,datum);

     }

}

 

LightClient.c:

 

El código del cliente fue hecho en C. Éste abarca desde la creación del socket hasta el envío de la información para el encendido y apagado de las luces. A continuación se muestra el código empleado:

 

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <string.h>

#include <netdb.h>

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

 

#define PORTNUMBER  8189

 

int main(int argc, char * argv[])

{

   int n, s, len;

   char buf[1024];

   char op1[]="ON";

   char op2[]="OFF";

   char hostname[64];

   struct hostent *hp;

   struct sockaddr_in name;

  

   switch(argc) {

     case 1:

       /* Get our local host name.  */

       gethostname(hostname, sizeof(hostname));

       break;

     case 2:

       /* Get name from command line */

       strcpy(hostname, argv[1]);

       break;

        default:

       printf("Usage: %s [server_name]\n",argv[0]);

       exit(-1);

    }

  

   /* Look up our host's network address.*/

   hp = gethostbyname(hostname);

  

   /* Create a socket in the INET domain.*/

   s = socket(AF_INET, SOCK_STREAM, 0);

  

   /* Create the address of the server. */

   name.sin_family = AF_INET;

   name.sin_port = htons(PORTNUMBER);

   memcpy(&name.sin_addr, hp->h_addr_list[0], hp->h_length);

   len = sizeof(struct sockaddr_in);

  

   /* Connect to the server. */

   connect(s, (struct sockaddr *) &name, len);

  

   /* Read from standard input, and copy the

     * data to the socket. */

   printf("Bienvenido al Switch en linea\n");

   printf("Para encender luces ingrese ON, para apagarlas ingrese OFF, para desconectarse del servidor ingrese BYE\n");

   printf("Como medida de seguridad, al inicar el cliente automáticamente apagará las luces de su casa\n");

  

   while ((n = read(0, buf, sizeof(buf))) > 0) {

      if (send(s, buf, n, 0) < 0) {

              perror("send");

              exit(1);

       }

      if((strcmp(buf,op1))==0)

            printf("Ha encendido las luces\nIngrese su opción: ");

     

      if((strcmp(buf,op2))==0)

            printf("Ha apagado las luces\nIngrese su opcion: ");

   }

  

   close(s);

   exit(0);

}

 

Como se puede apreciar, con un código muy simple (como el utilizado en la asignatura), fue posible establecer las conexiones cliente – servidor. Sin embargo, futuras actualizaciones de éste incluirán una GUI hecha en Java para tener el estado de las luces y a través de éste setear el encendido o apagado de las luces.

 

 

Conclusión:

 

Se lograron satisfactoriamente todos los objetivos propuestos inicialmente. Lo ideal habría sido agregar un GUI pero ésta puede ser agregada en una futura actualización del programa. Cabe destacar que podrían agregársele al sistema más características como sensores por ejemplo lo cual lo harían más completo y atractivo.

Se pudo controlar la puerta paralela mediante java, a pesar de que el archivo DLL no lo creamos nosotros ni lo estudiamos, pero damos un vínculo a él para futuras referencias.

 

 

Referencias:

 

  1. Apuntes de clases del profesor Agustín
  2. www.geocities.com/Juanga69/parport/
  3. http://www.hytherion.com/beattidp/comput/pport.htm
  4. http://java.sun.com/developer/Books/javaprogramming/cookbook/11.pdf

 

Anexos:

 

1.     Código java servidor

2.  Código C cliente

3.     Código fuente jnpout32.dll