lunes, diciembre 08, 2008

Diseño de redes inalámbricas con Radio Mobile (III)

Bueno, lo primero, mil perdones por tardar tantísimo en seguir escribiendo. Un pico de trabajo...que más bien se podría decir que ha sido una meseta de trabajo, me ha tenido ocupado durante muchísimo tiempo. En otra entrada explicaré tranquilamente en qué (QoS en enlaces WiFi de largo alcance sobre empotrados con GNU/Linux y driver madwifi). Pero ahora vamos a lo que nos ocupaba, ¡al turrón!

En las anteriores entradas (I y II), vimos cómo instalar una máquina virtual sobre una Ubuntu, en la que introdujimos un Windows XP, y que optimizamos para permitirnos instalar nuestro software Radio Mobile. Aprendimos también a descargarnos los mapas SRTM de la región sobre la que queremos diseñar nuestras redes inalámbricas y utilizarlos con Radio Mobile. Hoy trataremos de simular un enlace WiFi de largo alcance y comprobar qué calidad de señal obtendríamos de montar físicamente la red. Es cierto que en este caso jugamos con ventaja, pues la red ya está montada y está claro que funciona, pero aún así, descubriremos en el transcurso de la entrada que en nuestro diseño puede haber errores, y que el diseño no es único, probablemente a cada uno de vosotros os pudiera salir un diseño diferente y puedar ser todos buenos. La selección final vendrá dada también por las condiciones reales que no son emulables con nuestro software (ubicación de las poblaciones, posibilidad de acceso para instalación de repetidores, propiedad colectiva del terreno, negativa de la comunidad...y tantas otras posibilidades que pudieran ser determinantes fuera de lo que es el diseño puro y duro).

Como ya dijimos, vamos a centrar el mapa en un punto de nuestra red que esté situado más o menos a la mitad, para así poder tener una perspectiva de toda nuestra red cuando esté completada. Yo he escogido el Puesto de Salud de Rumi Tuni, así a ojo, cuyas coordenadas son 74º 42' 21.8''O - 1º 47' 39.7''S. Para hacerlo, pinchamos en "Archivo -> Propiedades del mapa", y ahí pulsamos en "Ingresar LAT LON o QRA". Introducimos las coordenadas. Pulsamos sobre la "N" para cambiarla a "S", es decir, en nuestro caso hablaremos de latitud sur, y dejamos la "O" como está pues queremos ingresar una longitud Oeste. Después de introducir las coordenadas, decimos "OK". Ahora introducimos una resolución de 2000 x 2000 pixeles y de altura unos 150 km, aunque ya veremos luego que con ésto no alcanzaremos a cubrir toda la red, pero nos sirve para poder ver la parte central de la red que será la que empecemos diseñando.

Ahora pulsamos "Extraer", y nos debería salir un mapa como éste:

Lo que estáis viendo es el río Napo, al que podéis ver que se le une en la esquina inferior derecha un pequeño afluente que zigzaguea desde muy lejos, ese es el río Curaray, en cuya confluencia con el Napo se encuentra uno de los puntos de la red (San Rafael). El resto de los puntos están en el Napo. Aquí hay que decir que en la realidad, Curaray arriba y muy lejos del resto de la red hay otro punto pero que no está conectado con tecnología WiFi, sino con VHF, y por eso no lo veremos aquí. Si os interesa tener más información de cómo EHAS comunica vía VHF los puntos más aislados, podéis escribirme al correo o buscar vosotros mismos la información en la página de EHAS.

Antes de crear un nodo cliente de la red, vamos a crear las redes y lo que en Radio Mobile se llama "Sistema", que son las propiedades que afectarán a los nodos en general. Para proceder con más limpieza, tenemos que diferenciar entre dos tipos de enlaces, los "Enlaces de distribución", que en la práctica serán los enlaces de los centros y puestos de salud de la región hacia sus torres repetidoras, y los "Enlaces troncales", que serán los enlaces entre las torres con antenas directivas que trasladen los datos entre la red a través de la selva. Para hacernos una idea más real, aquí pongo una foto de una estación cliente típica vista desde su torre y de la parte alta de una estación repetidora (en este caso las fotos son del P.S. de Tempestad, para que le pongáis cara a lo que estáis diseñando).
Estación cliente (la construcción con el techo verde):

Estación repetidora:

Enlace de distribución entre estación cliente y estación repetidora (se puede ver la antena cliente apuntando a la parte alta de la torre, donde está la antena del repetidor apuntando hacia el cliente):

Pues bien, como os imaginaréis, Radio Mobile tiene que tener parametrizadas las antenas que vamos a usar para poder simular los enlaces. El software por defecto trae ya algunas antenas, pero para nuestro caso vamos a usar otras, por lo que necesitaremos de los ficheros *.ant correspondientes a las antenas que queramos probar en nuestros enlaces. En esta red se han usado antenas tipo yagi de 9dBi diseñadas para 2,4GHz para los enlaces entre cliente y repetidor y antenas de grilla de 24dBi que trabajan en la misma frecuencia, pero podéis probar con otras antenas e incluso simular los enlaces en otras frecuencias (para WiFi podéis probar en 5,2 o 5,8GHz que son los otros rangos de frecuencias permitidos) y ver si sería posible establecer los enlaces. Los enlaces en altas frecuencias sufren más atenuación que en bajas frecuencias, y actualmente los drivers inalámbricos para tarjetas que trabajan en esas frecuencias no son del todo estables para largas distancias en linux, pero si queréis probar, ésto es software, haced cuanto os plazca.

En la sección de descargas públicas de la página web de la delegación Carlos III de Ingeniería Sin Fronteras, tenemos unos cuantos de estos ficheros, así que si queréis, podéis descargarlos. Luego los introducís en la carpeta "antenna" de vuestro Radio Mobile (típicamente C:\Radio_Mobile\antenna) y ya podréis usar estas antenas en el programa. Si analizáis el fichero de una antena, veréis que no es muy complejo, es un simple fichero de texto que almacena el diagrama de radiación de la antena escribiendo las ganancias con respecto al azimut y a la elevación haciendo mediciones cada 10º de separación, así que si os habéis fabricado una antena de forma casera y podéis medir su ganancia, ya sabéis que podríais crearos vuestro fichero .ant de la antena personalizada.

Antes de continuar, vamos a terminar de introducir todas las coordenadas de las unidades de nuestras redes. Me he dado cuenta de que en la entrada anterior os puse las coordenadas de las torres repetidoras de cada lugar, pero no de los centros y puestos de salud a los que dan servicio, así que vamos a hacer eso. Os pongo las coordenadas de todas las unidades:

Cabo Pantoja (Torre): 0º58'13,26''S 75º10'29,21''O
Torres Causana (Torre): 1º6'16,53''S 75º0'14,17''O
Tempestad (Torre): 1º17'22,81''S 74º52'27,42''O
Tupac Amaru (Torre): 1º21'46,55''S 74º44'42,89''O
Angoteros (Torre): 1º34'9,54''S 74º36'20,17''O
Campo Serio (Torre): 1º47'35,48''S 74º42'50,09''O
Rumi Tuni (Torre): 2º3'16,22''S 74º26'9,30''O
San Rafael (Torre): 2º22'1,43''S 74º6'42,91''O
Copal Urco (Torre): 2º20'23,41''S 73º47'26,23''O
Santa Clotilde (Torre): 2º29'22,07''S 73º40'41,02''O
Tacsha Curaray (Torre): 2º48'47,46''S 73º32'27,30''O
Cabo Pantoja (CS): 0º58'13,70''S 75º10'29,20''O
Torres Causana (PS): 1º6'16,61''S 75º0'14,48''O
Tempestad (PS): 1º17'21,28''S 74º52'28,94''O
Tupac Amaru (PS): 1º21'46,59''S 74º44'40,85''O
Angoteros (PS): 1º34'11,60''S 74º36'34,51''O
Campo Serio (PS): 1º47'39,70''S 74º42'21,80''O
Rumi Tuni (PS): 2º3'13,40''S 74º26'10,90''O
San Rafael (PS): 2º21'52,39''S 74º6'39,51''O
Copal Urco (PS): 2º20'56,50''S 73º47'23,30''O
Santa Clotilde (CS): 2º29'22,16''S 73º40'39,37''O
Tacsha Curaray (PS): 2º48'48,45''S 73º32'27,26''O

En nuestro esquema sabemos que vamos a tener 2 tipos distintos de estaciones: cliente y repetidor, así que lo primero que vamos a hacer es crear dos sistemas, uno para clientes y otro para repetidores.

Pinchamos en "Archivo -> Propiedades de redes" o directamente sobre el iconito que veis a la izquierda. Os saldrá un diálogo en el que podréis el nombre de vuestra red y demás asuntos, os pego cómo lo he dejado yo...


Canales de 802.11:
Canal 01: 2.412 Ghz.
Canal 02: 2.417 Ghz.
Canal 03: 2.422 Ghz.
Canal 04: 2.427 Ghz.
Canal 05: 2.432 Ghz.
Canal 06: 2.437 Ghz.
Canal 07: 2.442 Ghz.
Canal 08: 2.447 Ghz.
Canal 09: 2.452 Ghz.
Canal 10: 2.457 Ghz.
Canal 11: 2.462 Ghz.














Ahora la explicación de por qué lo he puesto así:
Necesitamos crear 2 tipos de redes, una para la red troncal, que podamos visualizar completa para ver una perspectiva de la red completa, y otra para las redes difusión, para ver cada estación si enlaza con su repetidor. En estas últimas, como luego querremos poder verlas aisladas una a una, y entre ellas no están enlazadas, creamos una subred para cada estación, mientras que en la troncal, también querremos poder ajustar cada enlace, por lo que introducimos también una red por cada enlace de red troncal.
Todas las redes tienen la misma configuración. Son redes de difusión, a las que le he agregado una pérdida adicional de un 20% por bosque (selva) y estamos en un clima continental sub-tropical.
¿Y por qué he puesto las frecuencias entre 2400 y 2474MHz? pues bien, en 802.11, tenemos los canales útiles que os pongo arriba. Las frecuencias que aparecen son las frecuencias centrales de cada canal, pero luego cada canal tiene un ancho de banda aproximado de 22.5MHz, por lo que usa 11.25MHz por abajo y 11.25MHz por arriba, así que redondeando a la alza diremos que usa 12MHz por arriba y 12MHz por abajo. Si restamos a la frecuencia central del primer canal 12MHz nos quedan 2400MHz (o 2.4GHz) y si sumamos 12MHz a la frecuencia central del último canal nos quedan 2474MHz (o 2.474GHz). El lector avisado se habrá percatado ya de que si el ancho de banda de un canal es de 22.5MHz y los canales tienen una separación de sólo 5MHz entre sí, los canales se solapan. ¡Efectivamente! Por eso decimos que en 802.11 (el estándar de WiFi) tenemos 3 canales no interferentes (el 1, 6 y 11). En realidad, serán canales no interferentes dos canales cualquiera que estén separados 5 canales (25MHz) entre sí, pero si escogemos los canales 1,6 y 11 tendremos 3 canales sin interferencias mientras que cualquier otra combinación sólo nos da 2 canales no interferentes. Ésto de escoger canales no interferentes es bastante importante, pues si dos estaciones están transmitiendo en frecuencias solapadas provocarán colisiones e interferencias entre sí que bajarán nuestra tasa de transferencia, y está claro que cuanto mayor tasa de transferencia tengamos, mejor servicio podremos prestar.

La selección del modelo estadístico accidental viene debida a que en este modelo no se nos solicita % de ubicaciones, y dado que nuestra red será fija, no queremos asegurar servicio en un cierto % de ubicaciones, sino un % de tiempo concreto. Los valores que ahí hay que poner en cada caso para optimizar aún están en estudio, así que los he fijado a los que Radio Mobile trae por defecto.

Lo siguiente que vamos a hacer es crear los distintos sistemas que formarán nuestra red. Os voy a ahorrar la búsqueda en los dispositivos del mercado contándoos lo que hay instalado en esta red. Diferenciamos 3 tipos de sistemas:
- Sistema cliente: los clientes enlazan con la torre a través de un router Linksys transmitiendo a 17dBm que dispone de una antena yagi de 9dBi de ganancia.
- Sistema repetidor (enlace de distribución): es la sección del repetidor que se encarga del enlace con el cliente. Dispone de una tarjeta CM9 transmitiendo a 17dBm y una antena yagi de 9dBi de ganancia.
- Sistema repetidor (enlace troncal): es la sección del repetidor que se encarga del enlace con los repetidores adyacentes. Dispone de una tarjeta inalámbrica Ubiquiti SR2, transmitiendo a 26dBm y una antena de grilla Hyperlink de 24dBi de ganancia.

Estos datos son muy importantes puesto que en función del tipo de emisor que tengamos sabremos cuánta potencia estamos suministrando a su antena, y en función de la antena sabremos cuánta ganancia estamos añadiendo al enlace. Para tener todos estos datos, nos vamos a las hojas de características de las tarjetas inalámbricas, antenas y cables coaxiales que usaremos y veremos la potencia que suministramos a nuestro sistema, las pérdidas en los cables y la ganancia de las antenas para nuestra frecuencia de trabajo de (2.4GHz). Aquí podéis ver las hojas de características:
Tarjeta CM9
Tarjeta SR2
Antenas grilla
Cable coaxial de bajas pérdidas LRM-400

En sudamérica, las normas que rigen sobre la potencia radiada equivalente y demás asuntos técnicos son las mismas que en EEUU. Ésto tiene una ventaja en nuestro caso, y es que en Europa, la PIRE (Potencia Radiada Equivalente) máxima es de 100mW mientras que en EEUU es de 1W. Tener un tope máximo de 1W nos permitirá alcanzar distancias mayores. También tenemos que tener en cuenta los canales en los que es capaz de trabajar nuestra tarjeta inalámbrica para el espectro WiFi de América. Por ejemplo, en la hoja de características de la CM9 vemos que trabaja desde los canales 1 al 11, lo que explica el por qué de que arriba sólo os haya puesto los primeros 11 canales de WiFi. Asimismo, también tendremos en cuenta que si queremos alcanzar distancias muy largas, deberemos escoger una modulación para nuestra señal que sea más robusta frente a errores. Si trabajamos a 6Mbps la modulación será tal que se podrán enviar menos bits por símbolo (la velocidad será inferior), pero habrá menor probabilidad de error, lo cual es bueno en un medio con tantos errores como es un clima tropical con mucha humedad, y además, cuando se trabaja en estas modulaciones las tarjetas inalámbricas tienen mayor sensibilidad (son capaces de demodular señales que llegan con menor potencia) y además transmiten con mayor potencia. Todo esto hará que si queremos llegar a distancias muy largas, lo mejor será establecer una tasa de transferencia de 6 Mbps. Para esta tasa, vemos que la tarjeta SR2 tiene una sensibilidad de -94dBm y una potencia de transmisión de 26dBm. Utilizar la más robusta de las modulaciones tendrá sentido para nuestros enlaces largos, pero para nuestros enlaces cortos (los que sirven la señal desde una torre a un puesto de salud) podremos perfectamente utilizar una tasa de transferencia de 54Mbps (máximo de 802.11g). Así pues, para 54Mbps la tarjeta CM9 (es la que usamos en los enlaces de distribución) tendrá una sensibilidad de -74dBm y una potencia de transmisión.

Bien, conocido ésto, nos pasamos a la pestaña de "Topología". En esta pestaña, símplemente tendremos que asegurarnos de que todas nuestras subredes creadas están visibles y tienen seleccionada topología "Red de datos. Topología estrella (Master/Esclavo)", tal como muestro a continuación...


Con todos estos datos ya podemos rellenar nuestra pestaña de "Sistemas". En nuestro sistema estamos usando 3 tipos de sistemas:

Sistema cliente...
formado por un linksys con antena yagi y unos metros de cable coaxial dependientes de la distribución del puesto o centro de salud.

Sistema repetidor (enlace distribución)...
formado por una tarjeta CM9 con antena yagi y un metro de cable coaxial.

Sistema repetidor (enlace troncal)...
formado por una tarjeta SR2 con antena de grilla hyperlink.

Pero para simplificar este ejemplo, vamos a suponer que el sistema del cliente y el del repetidor para el enlace de distribución fueran el mismo, es decir, que abajo en el puesto de salud no tuviéramos un linksys, sino otra tarjeta CM9 recibiendo. En cualquier caso, quede dicho que para un diseño más exaustivo habría que diferenciar estos dos sistemas. Pongo pantallazos de cómo he rellenado esta pestaña en función de los valores que obtenemos de las hojas de características que os puse arriba.


Sistema Troncal...













Sistema de Distribución...












El siguiente paso es la pestaña "Miembros". Ahora agregaremos cada unidad a la red a la que pertenece. Ésta parte es divertida, consiste en ir diciendo, para la red de distribución de tacsha, los miembros serán tachsa y el PS de tacsha, y así para todos los enlaces de distribución. Luego en los enlaces troncales ir añadiendo para tacsha-santa los miembros tacha curaray y santa clotilde, e indicando correctamente que el sistema que utilizarán será en este caso el sistema troncal, mientras en el anterior era el sistema distribución.
Tendremos que ir unidad a unidad ajustando también la altura de la antena, diciendo que no tome el valor del "Sistema", sino seleccionando "Otro" y estableciendo su valor a mano. Para que probéis, os pongo las alturas de las antenas de cada nodo:

Cabo Pantoja (Torre): 42m
Torres Causana (Torre): 45m
Tempestad (Torre): 60m
Tupac Amaru (Torre): 39m
Angoteros (Torre): 66m
Campo Serio (Torre): 66m
Rumi Tuni (Torre): 90m
San Rafael (Torre): 90m
Copal Urco (Torre): 54m
Santa Clotilde (Torre): 72m
Tacsha Curaray (Torre): 72m
Cabo Pantoja (CS): 3m
Torres Causana (PS): 3m
Tempestad (PS): 3m
Tupac Amaru (PS): 3m
Angoteros (PS): 3m
Campo Serio (PS): 3m
Rumi Tuni (PS): 3m
San Rafael (PS): 3m
Copal Urco (PS): 3m
Santa Clotilde (CS): 3m
Tacsha Curaray (PS): 3m

En cuanto al apuntamiento de las antenas, que ajustamos en "Azimut de Antena", tendremos que ir unidad a unidad diciendo que apunte correctamente a la unidad destino del enlace. Es un poco pesado, pero hay que hacerlo, ya que como tenemos antenas directivas, si no apuntamos bien, nuestro balance de enlace será una birria :). Os pego ejemplos de un enlace troncal y de uno de distribución.

Ejemplo del enlace de distribución de la torre de Tacsha Curaray con su Puesto de Salud:


Torre...













Puesto de Salud...












Ejemplo de enlace troncal entre la torre de Santa Clotilde con la de Copal Urco:


Torre de Santa Clotilde...













Torre de Copal Urco...












Y así a lo tonto, hemos casi llegado al final del diseño de nuestra red, sólo nos queda la pestaña "Estilo", que viene a ser la que nos dice con qué colorines nos pinta las líneas dependiendo de los dBs por encima de la sensibilidad de la tarjeta receptora en cada enlace. Normalmente, y debido a las variaciones que sufre un canal inalámbrico y más en entornos tan húmedos y lluviosos como la selva, diremos a Radio Mobile que nos pinte la línea verde sólo cuando nuestro "Rx Relativo" supere los 20dB, y que se ponga amarilla entre 3 y 20dB, lo que nos hará saber qué enlaces no se pueden conseguir con el diseño actual (línea roja), cuáles se podrían conseguir con ciertos retoques quizás (línea amarilla) y cuáles están bien dimensionados (línea verde). Os pongo un pantallazo de esta configuración...


Finalmente, ya tenemos toda nuestra red configurada, así que pulsamos en "OK" y vemos el resultado. La impresión inicial será...pufffff, ¿aquí no enlaza nada con nada o qué? Jeje, bueno, tranquilos, ésto se debe a que nuestras coordenadas GPS no eran del todo exactas, y habrá que afinarlas, pero no os preocupéis que eso lo haremos en la siguiente entrada. Ya habéis tenido bastante por hoy para llevar tanto tiempo sin currar en Radio Mobile :).

Y nada, a comer muchas verduras. Nos vemos en la siguiente entrada de "Diseño de redes inalámbricas con Radio Mobile".

¡A cuidarse!

martes, diciembre 02, 2008

Integración con SkypeWeb API desde ASP.net y Mono

Todos los códigos de este artículo os los podéis descargar desde:
  • Proyecto de Visual Web Developer Express 2005, aquí
  • Solución de Monodevelop, aquí

En este artículo vamos a ver una pequeña integración con el API de Skype para plataformas web. Lo que vamos a hacer es implementar un pequeño control de presencia que podremos utilizar en nuestra web. La idea es que, a través del API Web de Skype, interrogar sobre nuestro estado en Skype y, en base a la respuesta, mostrar un icono de estado.

¿Para qué nos puede servir esto, os preguntareis? Pues, por ejemplo, Skype es una muy buena opción para dar soporte a usuario y siempre queda bien poner un icono de que estamos online o no en nuestra página web. También sirve como base para cuando Skype ofrezca más servicios vía web, en fin, y como curiosidad.

Vamos al lío entonces...
Lo primero que tenemos que hacer es configurar Skype para permitirle que notifique nuestro estado. En Herramientas -> Opciones, en la pestaña Privacidad, marcaremos la opción "Mostrar mi estado de conexión en la web":




















Una vez marcada esta opción, el servidor de Skype permitirá que le interroguen sobre el estado de nuestro usuario a través de su API. Skype provee de dos métodos por los que obtener el estado de un usuario: vía consulta DNS, vía petición HTTP. Nosotros vamos a ver la segunda opción. La sintaxis para interrogar es la siguiente:

http://mystatus.skype.com/[nombre_usuario].extension

En [nombre_usuario] pondremos el usuario sobre el que queremos obtener el estado, en este caso, será el nuestro, y en extensión le indicaremos a Skype cómo queremos que nos devuelva la información. Disponemos de cuatro opciones:
  • Sin extensión: Skype devuelve una imagen con el estado del usuario (en la documentación se muestra las diferentes imágenes de que dispone)
  • xml: devuelve un XML con el estado del usuario en diferentes idiomas
  • txt: devuelve el estado del usuario en formato texto en el idioma del explorador
  • num: devuelve un código equivalente al estado del usuario (ésta es la opción que vamos a utilizar).
Lo que vamos a hacer, por lo tanto, es lanzar una petición http al servidor de Skype, obtener la respuesta y en base al código que nos devuelva, poner una imagen u otra en pantalla. Los posibles códigos de retorno son:
  • 0: desconocido
  • 1: offline
  • 2: online
  • 3: fuera
  • 4: no disponible
  • 5: no molestar
  • 6: invisible
  • 7: skype me


Vamos a codificar el asunto
La página de demo la podéis encontrar pinchando aquí

El proyecto está realizado tanto para Monodevelop (para los de Linux) como para Web Developer Express Edition 2005 (para los de Windows). La única diferencia es que Mono no dispone de soporte para el AJAX de ASP.net y en la versión de Mono está quitado el tema de AJAX.

La pantalla del proyecto es la siguiente:
















Introduciremos el nombre del usuario a interrogar y pulsaremos sobre el botón "Buscar desde Servidor". El código que se ejecuta en este botón es:
















Lo primero que se hace es realizar un HttpWebRequest hacia el servidor de Skype pasándole el usuario que se ha introducido en el textbox. Obtenemos la respuesta y creamos un Stream para ir leyendo el resultado que nos devuelve Skype.

Al leer el código de la respuesta, ponemos en pantalla una imagen correspondiente al estado del usuario. En la carpeta img disponemos de 8 imágenes llamadas 0.png, 1.png, 2.png,... en función del código devuelto, pondremos una u otra.

El resultado es el siguiente:
















En el proyecto de Web Developer, le he puesto un UpdatePanel para que no haya refrescos de pantalla, mientras que en Mono no está puesto.

Control de Presencia
Con esta pequeña integración podemos poner un icono en nuestra página web indicando nuestro estado en Skype. Tenemos dos alternativas:
  • Poner un timer para que vaya refrescando el estado cada x tiempo.
  • Realizar esta operación en el Page_Load y actualizar el estado solamente cuando se acceda a la página.
También existe la posibilidad de implementar las llamadas desde Javascript a través de un Proxy y manejar la respuesta directamente desde la página (en Javascript).

En fin, espero que os haya gustado este pequeño post, y que os sirva para investigar más allá y para poner vuestro icono de presencia en vuestras webs.

lunes, noviembre 03, 2008

Gráficos dinámicos con Open Flash Chart en ASP.NET y UpdatePanels

Todos los códigos de este post os los podéis descargar desde aquí. Todo el proyecto ha sido realizado con Visual Web Developer 2005 Express Edition.

Buenas, hace tiempo que tenía ganas de escribir este artículo sobre la creación de gráficos sobre ASP.NET utilizando la librería flash OpenFlashChart. Este componente flash nos permite crear gráficos muy versátiles, de muy diversos tipos y totalmente customizables en estilo. Además, es código abierto y libre tanto para uso personal como comercial. Aunque ya ha sido liberada la versión 2 (con cambios sustanciales en la forma de pasar los datos), este artículo está basado en la versión 1.9.7 que fue la que inicialmente me descargué en su momento y con la que trabajé.

Introducción del por qué y el cómo
En la página de OFC podéis encontrar multitud de ejemplos, tutoriales, foros, etc. por lo que no voy a explicar aquí los diferentes tipos de gráficos y las funcionalidades de las que dispone OFC.

Después de leer la documentación y de probar con la librería, me surgió un problema, la necesidad de pasarle datos dinámicamente desde código al gráfico y que se refrescará utilizando UpdatePanels de ASP.net. Es decir, poder generar, actualizar, cambiar el tipo de gráfico, todo ello desde código (entiéndase base de datos) y utilizando el AJAX de ASP.NET. Para conseguir tal propósito, me he apoyado en la librería .NET que viene con la descarga de OFC llamada "OpenFlashChartLibrary.dll". Esta librería trae un control de servidor para renderizar el gráfico, pero en este proyecto no se utiliza, sólo utilizaremos las clases que nos permiten generar el código de los gráficos que entiende el componente flash.

¿Qué es lo que queremos conseguir?
Puedes acceder a las páginas de demo pulsando aquí

Si véis en las páginas de demo, lo que queremos conseguir es un entorno basado en AJAX (UpdatePanels) para la generación y actualización de gráficos. En el ejemplo hay dos páginas:
  • La primera (Ejemplo de gráfico dinámico): permite generar un gráfico dinámicamente y anexarle dos series más. Además podemos elegir si cada serie la queremos en forma de barras o líneas. Si elegimos el gráfico como tarta sólo se renderiza la primera serie. Además el gráfico recalcula automáticamente los márgenes de valores máximos a mostrar en base a los datos introducidos (hay un error en la demo, sólo recalcula para la primera serie, lo siente).















  • La segunda (Ejemplo de varios gráficos): nos permite generar dos gráficos simultáneamente y actualizarlos de forma independiente, cada uno con sus controles de tipo de gráfico y la serie a mostrar.

















¿Cómo lo hacemos?
Todo el tema se basa en la clase RenderizadorGrafico.cs que se encuentra en la carpeta App_Code del proyecto. Dicha clase se apoya en la libreria OpenFlasChartLibrary para la generación del código del gráfico. El funcionamiento general es el siguiente:
  1. Le pasamos a la clase la primera serie a pintar junto con varios valores generales (título del gráfico, posiciones decimales, etc)
  2. Si tenemos más series le vamos pasando cada una de las series restantes (debe coincidir el número de valores de la serie con los del eje X), con su nombre.
  3. Llamamos al método RenderizarGrafico pasándole el código del gráfico (devuelto por los métodos anteriores), la ubicación del componente flash OFC, el div donde queremos que se coloque el gráfico y la página en la que estamos. Este método se encargará de generar el código javascript necesario para mostrar el gráfico y lo inyectará en la página.
La clase RenderizadorGrafico.cs en detalle
La clase RenderizadorGrafico.cs es la encargada de generar el código que entiende el componente OFC para la generación de los gráficos. Esta clase se apoya en la librería OpenFlashChartLibrary.dll que viene con OFC y que simplifica la generación del código. Los métodos de los que dispone la clase son:
  • RenderizarGrafico: se le pasa el código del gráfico (obtenido con los otros métodos), la ruta del componente OFC, el div donde colocar el gráfico (uno por cada gráfico) y la página que llama al método. Este método tiene una sobrecarga para cuando tenemos varios gráficos en pantalla en la que le pasamos arrays con los diferentes códigos y los divs donde colocar cada gráfico.
  • GenerarCodigoGrafico: este método se encarga de generar el código del gráfico que le pasaremos al método RenderizarGrafico. A este método le pasaremos la serie tanto para el eje X como para el eje Y y diferentes parámetros de visualización. Este método dispone de una sobrecarga para la representación de gráficos en forma de tarta que se manejan de forma diferente. En esta sobrecarga se le pasan los valores en formato Object[,], pasando en la primera dimensión el valor y en la segunda la etiqueta.
  • AnexarGrafico: este método permite anexarle más series a un gráfico.
La clase define al inicio el estilo que se va a aplicar para los gráficos, teniendo varios struct y constantes que se van utilizando a lo largo de los métodos. En cualquier momento se puede modificar dichos valores para cambiar el aspecto de nuestros gráficos.













La clase dispone, al final de un par de métodos que se utilizan para corregir ciertos fallos que me encontré en la librería .net en la generación de gráficos del tipo tarta.

¿Cómo genera la clase el gráfico?
La clase, en el método RenderizarGráfico, genera el código javascript necesario para renderizar el gráfico en pantalla. Utiliza el fichero swfobject.js para la incrustación de elementos flash en páginas web y lo inyecta en la página. Para inyectar el código hace uso del elemento ScriptManager del AJAX de ASP.net.














¿Cómo le pasamos los datos?
Tenemos dos formas de pasarle los datos a la clase dependiendo del tipo de gráfico que vamos a realizar. Si vamos a crear un gráfico que no sea del tipo tarta tendremos que crearnos lo siguiente:
  • Array de strings con los valores del eje X
  • Array de doubles con los valores del eje Y
  • Float con el valor máximo de la gráfica
  • Float con el valor mínimo
Si vamos a generar un gráfico del tipo tarta tendremos que crearnos lo siguiente:
  • Array de objects de dos dimensiones (object[2,numero elementos]) que tenga en la dimensión 0 el valor y en la dimensión 1 la etiqueta para ese valor. El componente se encargará de pintarlos en el orden correcto.
Lo último, ¿qué código ponemos en el aspx?
Finalmente, para que nuestro gráfico se vea correctamente tendremos que crearnos en la página un div donde vaya a ser colocado. Para utilizar AJAX en los refrescos del gráfico, pondremos dicho div dentro de una estructura UpdatePanel y le pondremos los triggers pertinentes.


















Final
Espero que os haya gustado este artículo y que os pueda servir. Personalmente, esta solución se encuentra en entornos de producción y funciona perfectamente. Como siempre, agradeceré cualquier comentario.

lunes, octubre 06, 2008

Inscripción al concurso de blogs del 20 minutos

He inscrito este blog en el concurso de la revista 20 minutos, en la categoría de mejor blog de tecnología. Si os gusta el contenido que publicamos aquí, os agradeceríamos que nos votaseis en cuanto empiecen las votaciones (15 de Octubre).

La dirección del concurso es http://www.20minutos.es/premios_20_blogs y el nombre con el que se ha inscrito éste es "N-Idea de muchos temas".

miércoles, agosto 27, 2008

Uso de Transacciones en C# con TableAdapters

Actualización (10-10-2008): el enlace correcto al artículo de Mike Pagel es http://www.codeproject.com/KB/dotnet/transactionta.aspx. Gracias Diego.
Actualización: ha habido un error con el enlace el artículo de Mike Pagel, podéis descargaros su clase desde la dirección http://www.nidea-soluciones.com/PruebasAJAX/TransactionSupport.zip

En este nuevo artículo voy a abordar el tema de la gestión de transacciones cuando trabajamos con TableAdapters generados por Visual Studio. El trabajo con TableAdapters generados por Visual Studio es muy cómodo, en el sentido que genera toda la lógica de acceso a datos y la representación de los mismos con Datatables, pero en el momento en que queremos utilizar transacciones en nuestros accesos a base de datos, el tema se complica. En determinados entornos, sobre todo a la hora de programar sistemas grandes, el uso de transacciones se vuelve inevitable. En este artículo vamos a ver una forma muy cómoda de usar transacciones con TableAdapters generados por Visual Studio.

Un poquito de teoría
Antes de nada, vamos a ver un poco cómo va el tema de las transacciones. ¿Para qué sirven las transacciones? Una transacción lo que nos permite es controlar un grupo de sentencias a base de datos de forma que podamos o bien dar marcha atrás a todas las sentencias o bien confirmar el bloque completo. El control del grupo de sentencias lo lleva la base de datos, de forma que el programador sólo debe indicar si se confirma (Commit Transaction) o no (Rollback Transaction) el grupo de sentencias. En el siguiente dibujo os pongo un ejemplo:





Como podéis ver, desde el momento en el que iniciamos la transacción, todas las operaciones quedan registradas y si realizamos un rollback deshacemos las hechas y si hacemos un commit, la transacción se termina y los cambios quedan confirmados.
Pero, ¿qué pasa si hacemos un select sobre un campo actualizado en una transacción no confirmada? Buena pregunta, porque se plantea un problema, si la sentencia no está confirmada, el gestor de base de datos no puede asegurar que ese dato sea correcto. En ese caso entran en juego los niveles de aislamiento de transacciones (Isolation Levels) que, básicamente, lo que deciden es cómo se debe comportar el gestor de base de datos en estas situaciones.

Bueno, al lío
Vamos a ir paso a paso, lo primero que vamos a hacer es crearnos una aplicación de Windows Forms en C# (me supongo que sabéis hacerlo). Para todo vamos a utilizar la versión gratuita (Express) de visual studio, en concreto Visual C# 2005 Express Edition.

1. Crearse un proyecto "Aplicación para Windows"
2. En la pantalla principal nos creamos los siguientes controles











3. Nos creamos una nueva base de datos en SQL Server 2005 Express Edition que se llame "PruebaTransacciones" con una tabla llamada "Tabla1" que contenga 2 campos "Id" y "Nombre" y otra llamada "Tabla2" con los mismos campos. La definición es la siguiente:
























4. Nos creamos en nuestro proyecto dos TableAdapters, uno para cada una de las tablas que hemos creado en base de datos.















Por ahora, nuestro proyecto y los TableAdapters nos tienen que quedar de la siguiente manera:









Ahora mismo no disponemos de soporte para transacciones porque los tableadapters generados no lo incluyen. Es en este momento cuando le vamos a introducir esa nueva funcionalidad. Vamos a utilizar una clase creada por Mike Pagel y que podéis encontrar en su artículo del CodeProject http://www.codeproject.com/useritems/typed_dataset_transaction.asp. Lo que vamos a hacer es sobreescribir la clase base de los tableadapters con esta que incorpora las funcionalidades de las transacciones. Para ello, incluiremos la clase en nuestro proyecto y en las propiedades de los TableAdapters, pondremos el nombre de la clase en la propiedad BaseClass:










En mi caso le he puesto Transaccion.TransactionSupport porque el namespace de la clase es Transaccion.

Utilizar las transacciones
Ahora que tenemos soporte para transacciones vamos a utilizarlas en nuestra pantalla. Teníamos creados un botón y dos radiobuttons, vamos a programar el evento Click del botón de la siguiente manera:






















Lo que hacemos es insertar un registro en la tabla1 y confirmamos o deshacemos la operación en base a los radiobuttons que se pusieron. Ahora vamos a modificar un poco el código para realizar una operación sobre las dos tablas compartiendo la transacción:
























En este caso, hemos igualado la transacción secundaria con la principal para poder interactuar con varias tablas a la vez. El último paso es: ¿cómo pasar una transacción por diferentes clases y métodos para actuar sobre múltiples tablas sin tenerlo todo en el mismo método? La pregunta es larga pero la respuesta es corta, veamos la siguiente modificación al método del botón:






















En este caso, estamos instanciando la clase ManejadorTabla2 y llamando al método ActualizarTabla para guardar los cambios en la tabla2. A este método, aparte de los registros le estamos pasando la transacción. El código interno del método es el siguiente:






















Lo que hacemos en este método es controlar si se pasa como argumento una transacción o no. Si el método falla, lo que hacemos es devolver un false para el método que controla la transacción decida qué hay que hacer. En caso que no se pase transacción, el método se comporta de forma normal.

Conclusión
Ciertamente, el uso de transacciones en entornos grandes es obligatorio. No nos podemos plantear un sistema sin control de transacciones porque antes o después se haría inviable su programación. Creo que esta solución al problema es muy simple, elegante y efectiva y os animo a probarla. Como siguiente paso para el que guste de estos temas queda la modificación de la clase para adaptarlas a entornos no SQLServer como puede ser MySql. El código es muy sencillo y creo que se podría modificar rápidamente.

En fin espero que os haya gustado este articulillo sobre transacciones.

jueves, julio 03, 2008

Motor de Informes Dinámicos con itextsharp (II)

Hola de nuevo a todos, ha pasado un tiempo desde la primera parte del tutorial, pero ya he encontrado tiempo para escribir esta segunda parte (más interesante que la primera). En la primera parte vimos cómo funcionaba la librería itext# para generar informes PDF al vuelo. En esta segunda parte lo que veremos será cómo crear plantillas XML para juntarlas posteriormente con datos y generar el PDF.

El inicio de todo
Lo que vamos a hacer es por un lado, crearnos una plantilla XML con parámetros, por otro lado, generar nuestros datos en formato XML (para poder guardarlos en base de datos) y finalmente, juntar las dos cosas y obtener, al vuelo, la plantilla con los datos en formato PDF.

El flujo de datos

El funcionamiento del sistema de plantillas es el siguiente.

















Desde la página obtenemos los datos en XML y la plantilla, lo cual va en sesión a la página ImpresionPDF.aspx. Esa página se encarga de llamar a la clase ParseadorPDF.cs que es la que contiene la lógica de negocio para generar el PDF al vuelo. Esa clase devuelve un MemoryStream con el PDF a la página, la cual lo renderizará en pantalla.

La plantilla XML
El primer paso es generarnos la plantilla XML con los tags adecuados que entienda la librería. Para un ejemplo de los tags que se pueden utilizar, en la ayuda nos ofrecen algunos ejemplos. Nosotros vamos a trabajar con el siguiente XML que es muy sencillo:






















En este informe utilizamos diferentes tags, como: table, row, cell, newline, itext(obligatorio al inicio y al fin) y en medio hemos introducido tags propios:nomAE, numAE, nomAl y dniAl. Estos serán los parámetros que se sustituirán posteriormente por los valores que le digamos. La librería itextsharp tiene un problema a la hora de parsear los XML en PDFs y es que NO PUEDE TENER ESPACIOS EN BLANCO DENTRO DE LOS TAGS TABLES. Es decir, para generar una plantilla XML, no podemos indentarla, sino que tiene que ir como se muestra en la imagen o dará un error de ejecución.

Los datos a parsear
En este paso, lo que vamos a ver es cómo pasarle los datos que queremos que aparezcan en el informe a la librería para que los junte correctamente. Le vamos a pasar un vector con dos dimensiones, en una dimensión irá un esquema XML con los datos a imprimir y en la otra irá la plantilla a utilizar. El esquema XML es como el siguiente:













A la hora de crear el documento veremos cómo crear este esquema XML para guardarlo en base de datos. Una vez recuperado el documento XML, la creación del vector es la siguiente:








En el vector de objetos “datos” guardamos el XML y la plantilla correspondiente. Seguidamente llamamos a la pantalla ImpresionPDF.aspx que se encargará de generar la plantilla XML.


La página ImpresionPDF.aspx

Esta página es la encargada de recibir los datos desde la sesión y llamar a la clase encargada de generar el PDF. Además de esto, obtiene de base de datos los márgenes a aplicar, las dimensiones del PDF y varios datos de formato propios de la plantilla. Una vez recuperados estos datos llama al método GenerarPDF de la clase ParseadorPDF:








El método devuelve un MemoryStream con el fichero PDF para ser renderizado. Veamos ahora cómo se produce el parseo real de los datos.


La clase ParseadorPDF.cs

Esta es la clase que se encarga de juntar las plantillas con sus respectivos datos. El flujo es el siguiente:

1. Crear el PDF global que va a ser devuelto y ponerle las dimensiones precisas:






2. Recorrer los datos y plantillas pasadas para ir tratando a cada una de ellas. Este método permite que se pasen a la vez varios XML de datos con varias plantillas en el mismo vector de objetos, por lo que lo primero es ir recorriendo las diferentes plantillas. Para cada XML de datos realizamos una conversión a un vector de objects con los datos que es lo que entiende el método:






3. Para cada plantilla con sus datos los juntamos en un PDF temporal que es guardado en una ruta temporal y posteriormente anexado al PDF global que se creó al inicio. En esta parte es donde se realiza la unión real de los datos, creando un hashtable que enlaza cada parámetro con su valor y llamando al método Parse de la librería PDF:












4. Una vez realizado el parseo, lo que tenemos que hacer es eliminar los ficheros temporales que hemos ido creando en el proceso. Estos ficheros se encuentran guardados en la variable subFicheros.

El método ParsearDatos

Este método es el encargado de crear un hashtable que enlace cada parámetro con su valor. Lo primero es crear el hashtable y asignarle los primeros valores fijos:














Seguidamente, para cada parámetro, tendremos que unirlo con su parámetro y asignarle un XMLPeer correcto:











Dependiendo del tipo de parámetro que sea será tratado de una forma o de otra, lo que rellenamos en el método es la propiedad peer.Content con el valor del parámetro y si le queremos incluir más atributos rellenamos la propiedad peer.AddValue.


El método ConcatenarPaginas

Este método se encarga de unir las páginas de los PDF temporales que creamos con la del PDF global que será devuelto a la capa de presentación. El código de este método es el siguiente:












El final

Bueno, con esto termino el artículo. Espero haberos dado una idea inicial de cómo realizar un motor de plantillas basado en XML para la librería itextsharp. No he podido explicar el funcionamiento completo porque eso exigiría muchísimo tiempo pero creo haber ahondado bastante para que podáis seguir vosotros.


Como siempre, para cualquier duda que os surja aquí estoy.