Proyecto de Control Remoto por Intranet o Internet usando el puerto paralelo
por Daniel Solowiej
NOTA: Si bien el proyecto aquí expuesto funciona perfectamente en mi entorno de prueba y para mis pretensiones, NO me hago responsable por ningun daño directo o indirecto ocasionado por la aplicación práctica o teórica de este material. Por favor revise cuidadosamente las conexiones y polaridades de sus circuitos antes de conectarlos a la pc dado que puede provocarle un daño irreversible. Tampoco me hago responsable del correcto funcionamiento de los circuitos y de los ejemplos aquí explicados. Declino toda responsabilidad respecto a lo enunciado y a sus consecuencias.
OBJETIVO
Control remoto de toda clase de dispositivos con alimentación eléctrica (máquinas en general, iluminación, robótica, motores, puertas, manejo de materiales peligrosos), por intranet o bien internet usando un browser y el puerto paralelo de la pc.
INTRODUCCION
Este proyecto nace por la necesidad de controlar a distancia determinados dispositivos y máquinas , que deben funcionar durante muchas horas en mi taller sin presencia humana. Pero es aplicable a cualquier situación eléctrica que amerite un control a distancia, incluso desde cualquier lugar del mundo en el que se cuente con acceso a internet, necesitando en dicho caso los lógicos ajustes para su funcionamiento.
Como en mi caso particular, el control necesario es local (desde la planta baja a la planta alta de mi casa), solo me referiré aquí a la implementación de un control por intranet, que por estar lógica y físicamente aislada de internet u otra Wan, no requiere la atención necesaria a los aspectos de seguridad tradicionales respecto a intrusiones.
Si bien no es planteado aquí, es factible ampliar este proyecto a funciones de telemetría sin muchas modificaciones, utilizando los cinco pines de estado del puerto paralelo e incluso una placa multiplicadora para aumentar la cantidad de sensores.
DESARROLLO
Presento aquí un esquema del proyecto.

En la parte superior (en mi caso el taller de la planta alta), tenemos una pc que oficia de servidor (S) , un router (R) , una cámara IP (C) , y por último un driver para puerto paralelo (D) , en mi caso un buffer/driver que multiplica a 32, las 8 salidas del puerto paralelo de la pc.
En la parte inferior (en mi caso el escritorio de la planta baja) vemos una pc cliente (L) .
SISTEMAS OPERATIVOS USADOS
Puppy Linux 3.01 retro en pc servidor. Puppy Linux 2.17 en pc cliente. Linux embebido en cámara IP.
INTRANET
Fué estructurada con cable utp categoría 5 para exteriores. (demás está decir que puede usarse Wifi o cualquier otro medio inalámbrico u óptico). Largo del cable entre cliente y router = 14 metros. Tiempo promedio del comando Ping al servidor = 0 ms / 0.5 ms.
LAN compuesta por estas direcciones IP: 192.168.0.10 (pc servidor), 192.168.0.1 (router), 192.168.0.20 (camara ip), 192.168.0.11 (pc cliente). No trataré aquí como configurar una red doméstica en Puppy-Linux ni temas relacionados al reconocimiento de las placas ethernet y la carga de los módulos correspondientes, dado que estos temas han sido extensamente desarrollados en el Foro de dicho sistema operativo y en su Wikki, por muchos colegas, y escapan al propósito de este texto.
http://www.murga-linux.com/puppy/
SERVIDOR DE PAGINAS WEB UTILIZADO
Ghttpd, sobradamente sencillo y suficiente para esta aplicación. En caso de que no funcione correctamente, la solución mas comun es matar todos los procesos httpd ,
|
# killall httpd |
hasta que no quede ninguno, y modificar el archivo de configuración, cambiando localhost a any.
Luego volver a arrancar el ghttpd.
Revisar el seteo del firewall de ser necesario, para que permita el trafico http.
PUERTO PARALELO
Si bien puede utilizarse el puerto paralelo onboard, siempre es conveniente utilizar un segundo puerto paralelo adicional para este tipo de funciones. Dado que este puerto tiene limitaciones respecto a la corriente que puede soportar en sus pines. Se debe tener especial y continuo cuidado en todo lo relacionado a él. En caso de usar un puerto paralelo PCI y tener problemas para acceder a él, recomiendo leer mi post en el Foro sobre una experiencia al respecto.
http://www.murga-linux.com/puppy/viewtopic.php?t=28686
DRIVER/BUFFER
En mi caso, diseñe mi propio circuito, modificando algunas cosas de circuitos encontrados en la web, para poder tener 32 salidas de 12V, algunas con relays de salida conmutada, otras directas (para motores paso a paso), y agregando la placa suplementaria que se ve mas abajo, seis salidas de 220V conmutadas.

Este es el diagrama del circuito (sin las leds) :

Aquí vemos la placa suplementaria para trabajar exclusivamente con 220 voltios. Tiene seis entradas que se conectan a seis de las salidas del buffer/driver y cuenta con seis salidas conmutadas (es decir que pueden utilizarse como normal abierto o normal cerrado, duplicando asi las tipologías de conexión a doce):

Por último para evitar los ruidos de línea utilizé un cable paralelo con filtro incorporado. Esto da estabilidad a las señales aún en lugares en los que existan grandes modificaciones y picos en la carga de la red, por lo que la actividad de motores o tubos fluorecentes no afecta la solidez de las señales del puerto.

/////////////////////////////////////////////////////////////////////
Un circuito muy fácil de hacer:
Para simplificar aquí las cosas consideremos que es perfectamente posible utilizar un circuito simple como el siguiente, que permite usar las señales de salida D0 a D7 del puerto y manejar ocho salidas de 12V con una intensidad máxima de 500 ma, aprovechando el circuito integrado ULN2803. Es siempre muy recomendable no soldar directamente circuitos integrados a la placa, es mejor usar zócalos. De éste modo protegemos los circuitos integrados del calor del soldador y los podemos reemplazar facilmente si se queman.

/////////////////////////////////////////////////////////////////////
CAMARA IP (C)
Opté por una cámara con servidor embebido, porque ademas de afectarla a otros usos domésticos, simplifica bastante el acceso por html a una imágen ya grabada en dicho servidor. En mi caso la ruta de la imágen es http://192.168.0.20/IMAGE.jpg -
De este modo es simple incluir la vista actual de la camara en un frame html simplemente usando un tag como este:
|
<img src=”http://192.168.0.20/IMAGEZ.jpg”> |
Además, en el caso de utilizarse internet, es posible enviar directamente desde la cámara, las imágenes por ftp y por e-mail.
PAGINAS HTML, SCRIPTS CGI
La interfase presentada a la pc cliente, está compuesta por paginas web codificadas en lenguaje html, accesibles mediante cualquier programa browser (navegador). Las páginas son estáticas no dinámicas pero se actualizan con un refresh automatico colocado en <head>.
La acción de encender un dispositivo remoto sigue esta secuencia:
1- El usuario hace un click en el link “ON” de un equipo determinado.
2- El link carga el shell-script cgi correspondiente a esa acción en otro frame dando a su vez cierta información adicional.
3- El shell-script sobreescribe la imágen asociada a dicho dispositivo (led roja) con otra (led verde), y borra si es que existe, un archivo que simboliza el estado de apagado del equipo llamado “no + numero equipo”. Dejando esta información para que el software la lea.
La acción de apagar un dispositivo remoto sigue esta secuencia:
1- El usuario hace un click en el link “OFF” de un equipo determinado.
2- El link carga el shell-script cgi correspondiente a esa acción en otro frame dando a su vez cierta información adicional.
3- El shell-script sobreescribe la imágen asociada a dicho dispositivo (led verde) con otra (led roja), y crea un archivo que simboliza el estado de apagado del equipo llamado “no + numero equipo”. Dejando esta información para que el software la lea.
Por tanto, el trabajo de los CGI se limita a sobreescribir archivos de imagen (los que mantienen su nombre pero no su contenido) , y borrar o crear (según sea el caso de encender o apagar) un archivo que representa el estado de apagado para cada equipo.
Los archivos de imagen son los que permiten ver el estado de cada equipo por medio de la página web. Los archivos que representan el apagado de un equipo son solo usados para que el software comprenda que debe poner la salida de ese equipo a cero.
Este es un esquema simplificado del funcionamiento:

Código real de un cgi que usé en el proyecto:
|
#!/bin/sh |
EL SOFTWARE DE LECTURA Y COMANDO
Por ultimo un software desarrollado al efecto corre continuamente en un bucle, efectuando la lectura de los archivos “no + numero equipo”, en virtud de los que encuentra y de los que no encuentra, realiza el calculo binario correspondiente a la salida final en bytes que debe entregar al puerto paralelo y envia las señales al mismo en formato decimal.
Es importante desactivar cualquier programa que ponga en hibernación la pc servidor o que active protectores de pantalla o desactive discos rígidos, de modo que el software de lectura y comando no sea perturbado por esas acciones.
En mi caso programé un software muy simple que corre en modo consola usando el lenguaje Freebasic.
Los requerimientos de sistema son realmente bajos por tanto la pc servidor puede ser muy antigua y no necesita servidor X para trabajar.
Está en una etapa Alpha, pero pongo aquí el código para quien quiera tener una base posible de trabajo. Debe considerarse que está escrito para trabajar con el buffer/driver de 32 salidas, de modo que si se usa solo un circuito simple de ocho salidas, el software será tambien mas sencillo.
|
#include "vbcompat.bi" Dim shared addressport as integer Dim shared filename As String Dim shared binadeci as integer Dim shared abi as integer Dim shared abi1 as integer Dim shared abi2 as integer Dim shared abi3 as integer Dim shared abi4 as integer Dim shared abi5 as integer Dim shared abi6 as integer Dim shared abi7 as integer Dim shared abi8 as integer Declare sub inicio Declare sub salidas Declare sub enviar Declare sub imagenes Declare Function ioperm Cdecl Alias "ioperm" (Byval Portbase as integer,Byval nPorts as integer,Byval value as integer) As integer addressport = &hde00 ioperm(addressport,5,1) imagenes inicio salidas '--------------------------------------------------------------- sub imagenes shell "cp /root/ghttpd/htdocs/nol.gif /root/ghttpd/htdocs/leds/21.gif" shell "cp /root/ghttpd/htdocs/nol.gif /root/ghttpd/htdocs/leds/22.gif" shell "cp /root/ghttpd/htdocs/nol.gif /root/ghttpd/htdocs/leds/23.gif" shell "cp /root/ghttpd/htdocs/nol.gif /root/ghttpd/htdocs/leds/24.gif" shell "cp /root/ghttpd/htdocs/nol.gif /root/ghttpd/htdocs/leds/25.gif" shell "cp /root/ghttpd/htdocs/nol.gif /root/ghttpd/htdocs/leds/26.gif" shell "cp /root/ghttpd/htdocs/nol.gif /root/ghttpd/htdocs/leds/27.gif" shell "cp /root/ghttpd/htdocs/nol.gif /root/ghttpd/htdocs/leds/28.gif" shell "touch /root/ghttpd/htdocs/leds/no21" shell "touch /root/ghttpd/htdocs/leds/no22" shell "touch /root/ghttpd/htdocs/leds/no23" shell "touch /root/ghttpd/htdocs/leds/no24" shell "touch /root/ghttpd/htdocs/leds/no25" shell "touch /root/ghttpd/htdocs/leds/no26" shell "touch /root/ghttpd/htdocs/leds/no27" shell "touch /root/ghttpd/htdocs/leds/no28" sleep 20 return end sub '--------------------------------------------------------------- sub inicio 'setea variables a cero cls binadeci = 0 abi = 0 abi1 = 0 abi2 = 0 abi3 = 0 abi4 = 0 abi5 = 0 abi6 = 0 abi7 = 0 abi8 = 0 ' inicializa puerto out addressport, 0 sleep 10 out addressport+2, 4 sleep 10 out addressport+2, 11 sleep 10 end sub '----------------------------------------------------------------------------------------- sub salidas '-------------- rastrea imagenes de salida do filename = "/root/ghttpd/htdocs/leds/no21" If FileExists( filename ) Then abi1 = 0 else abi1 = 00000001 end if filename = "/root/ghttpd/htdocs/leds/no22" If FileExists( filename ) Then abi2 = 0 else abi2 = 00000010 end if filename = "/root/ghttpd/htdocs/leds/no23" If FileExists( filename ) Then abi3 = 0 else abi3 = 00000100 end if filename = "/root/ghttpd/htdocs/leds/no24" If FileExists( filename ) Then abi4 = 0 else abi4 = 00001000 end if filename = "/root/ghttpd/htdocs/leds/no25" If FileExists( filename ) Then abi5 = 0 else abi5 = 00010000 end if filename = "/root/ghttpd/htdocs/leds/no26" If FileExists( filename ) Then abi6 = 0 else abi6 = 00100000 end if filename = "/root/ghttpd/htdocs/leds/no27" If FileExists( filename ) Then abi7 = 0 else abi7 = 01000000 end if filename = "/root/ghttpd/htdocs/leds/no28" If FileExists( filename ) Then abi8 = 0 else abi8 = 10000000 end if ' construye el binario final abi = abi1 + abi2 + abi3 + abi4 + abi5 + abi6 + abi7 + abi8 binadeci = Val("&b" + Str(abi)) print "Enviando Binario " ; abi ; " al puerto paralelo - DECIMAL( " ; binadeci ; " )" enviar Loop until inkey = Chr(27) ' inicializa puerto out addressport, 0 sleep 10 out addressport+2, 4 sleep 10 out addressport+2, 11 sleep 10 imagenes print "Enviando Binario " ; abi ; " al puerto paralelo - DECIMAL( " ; binadeci ; " )" print "Puerto Limpio" print "Programa cerrado" end sub '---------------------------------------------------------------------------- sub enviar out addressport, binadeci sleep 10 out addressport+2, 9 sleep 10 out addressport+2, 11 sleep 50 return end sub '_____________________________________________________________ |
PUESTA EN MARCHA DEL SERVICIO
Verificar todas las conexiones y sus polaridades antes de conectar la/s placa/s a la pc.
Conectar la/s placa/s con la pc apagada.
Iniciar sistema del router y esperar a que cargue.
Iniciar sistema de la cámara IP y esperar a que cargue.
Iniciar sistema de la pc servidor. (si no es necesario no iniciar servidor X o salir al prompt luego, dado que este servicio no lo necesita funcionando)
Iniciar servidor de páginas web Ghttpd o el que guste.
Iniciar software de lectura y comando.
Apagar el monitor de pc servidor (si es que se usó para iniciar sistema, ya que no se necesita usar mas).
Ya esta todo listo para acceder desde cualquier pc cliente por browser y usar el servicio.