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
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:
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:
Anexos: