lunes, 22 de septiembre de 2008

Monitorear UPS desde GNU/Linux

Recientemente compramos una UPS APC CS 500 para el servidor del CENEHA (mi trabajo). Como la mayoría de los fabricantes de hardware el software de monitoreo que incluye en el cd es para window$, y por lo tanto no me sirve para un carajo.

Por suerte el software libre tiene motorcito propio y siempre -o casi siempre- encontrás algún paquete que te sirve para llevar a cabo tu objetivo: monitorear la UPS desde GNU/Linux.

El modelo CS 500 posee un cable para conectar la UPS al servidor, del lado de la PC es un conector USB y en el otro extremo un RJ-45. Una vez realizada la conexión pasamos a instalar el software que dialogará con la batería.

El tema fue bastante más sencillo de lo que creía, simplemente se deben instalar los siguientes paquetes (www.apcupsd.org): apcupsd, apcupsd-cgi y apcupsd-doc:

#aptitude install apcupsd acpupsd-cgi apcupsd-doc


Una vez instalado pasamos a la configuración, en el archivo /etc/apcupsd/apcupsd.conf se deben establecer los parámetros que le indican -entre otras cosas- el tipo de conexión (USB, serial, etc). Este archivo es muy explicativo, así que si no se entiende lo que escribo acá, basta con leer las instrucciones del mismo y no hay manera de pifiar.

Bien, en mi caso tuve que poner modificar los siguientes parámetros:

UPSCABLE usb
UPSTYPE usb
DEVICE

NOTAR que luego de DEVICE se deja en blanco.

Por último, lo que nos queda es ejecutar el script que nos devuelve los parámetros encuestados a la UPS:

#apcaccess

APC : 001,043,1025
DATE : Mon Sep 22 16:49:13 ART 2008
HOSTNAME : ceneha
RELEASE : 3.14.2
VERSION : 3.14.2 (15 September 2007) debian
UPSNAME : ups
CABLE : USB Cable
MODEL : Back-UPS CS 500
UPSMODE : Stand Alone
STARTTIME: Fri Sep 19 14:39:21 ART 2008
STATUS : ONLINE
LINEV : 228.0 Volts
LOADPCT : 23.0 Percent Load Capacity
BCHARGE : 100.0 Percent
TIMELEFT : 28.1 Minutes
MBATTCHG : 5 Percent
MINTIMEL : 3 Minutes
MAXTIME : 0 Seconds
OUTPUTV : 230.0 Volts
SENSE : Medium
DWAKE : 000 Seconds
DSHUTD : 000 Seconds
LOTRANS : 180.0 Volts
HITRANS : 266.0 Volts
RETPCT : 000.0 Percent
ITEMP : 29.2 C Internal
ALARMDEL : Always
BATTV : 13.5 Volts
LINEFREQ : 50.0 Hz
LASTXFER : Low line voltage
NUMXFERS : 0
TONBATT : 0 seconds
CUMONBATT: 0 seconds
XOFFBATT : N/A
SELFTEST : NO
STATFLAG : 0x07000008 Status Flag
SERIALNO : 4B0824P03005
BATTDATE : 2008-06-10
NOMOUTV : 230
NOMINV : 230
NOMBATTV : 12.0
FIRMWARE : 808.q8.I USB FW:q8
APCMODEL : Back-UPS CS 500
END APC : Mon Sep 22 16:49:27 ART 2008


Y ahí tenemos toda la data que nos puede llegar a interesar sobre lo que está pasando con nuestra UPS, voltaje de la linea, frecuencia, etc.

Un detalle que acabo de encontrar es un programa cliente que nos muestra gráficamente estos valores, para mi caso no me sirve porque el servidor es interno y no tenemos acceso desde internet, sin embargo a alguien que tenga una pc cliente o un servidor con interfaz gráfica les puede interesar. El programa se llama gapcmon cuya interfaz -que no es un picasso- es muy fácil de manejar e interpretar, aquí les dejo una captura:


Para la próxima les prometo un script para obtener esta información y luego graficarla usando cacti.

miércoles, 17 de septiembre de 2008

Caracteres en un archivo binario usando C++

Escribir y leer datos en un archivo binario no presenta demasiadas dificultades. Por ejemplo, para escribir un entero "e" y un float "f" en un archivo binario "bin" hacemos lo siguiente:


int e=10;
float f=12.5;
fstream bin("archivo.bin", ios::binary|ios::out);
bin.write((char *)&e, sizeof(int));
bin.write((char *)&f, sizeof(float));
bin.close();


Todo es lindo y prolijo, ahora, qué pasa si tengo una cadena de caracteres al estilo C de 14 caracteres?

Bien, las cadenas de caracteres al estilo C son vectores de bytes, y por lo tanto el identificador de la variable es un puntero a la dirección de memoria del primer caracter. O sea que para escribir este flujo de 14 bytes debemos ir iterando y guardar dato por dato. Vamos a los bifes, supongamos que tenemos una cadena "pianobar":


char pianobar[14]="nace una flor";
fstream bin("archivo.bin", ios::binary|ios::out);
for (int i=0;i<14;i++){
bin.write((char *)&pianobar[i], 1)
}


Ahora, vamos a leer esta cadena:

char pianobar[14];
fstream bin("archivo.bin", ios::binary|ios::in);
bin.read((char *)&pianobar, 14)



De lo anterior vemos que la escritura se hace caracter por caracter, dejando un espacio de 1 byte por cada uno, luego al momento de leer el dato, se indica la cantidad total de bytes (para el ejemplo 14) y se asigna a la variable.

El único detalle a tener en cuenta es que la longitud de la cadena que hemos definido es de 14, sin embargo posee un máximo de 13 caracteres, ya que el último caracter queda reservado para el siguiente código de finalización "\0". Otro punto a tener en cuenta es que las cadenas, al igual que los vectores comienzan en la posición 0.

lunes, 15 de septiembre de 2008

getline luego de cin

Desde no hace mucho estoy intentando aprender C++. Viste que todo el mundo te dice: "Un informático no puedo no saber C++...", así que como creo que tienen algo de razón encaminé mi vida por el sendero del qué dirán.

C++ tiene muchas diferencias con respecto a otros lenguajes, no es solo aprenderse la nueva sintaxis, sino que existen nuevos conceptos previamente inexistentes para mi. Aparte de esto, a veces me encuentro con pequeños detalles pelotudos que me hacen renegar. Uno de esos detalles "pelotudos" se me dio este fin de semana: Simplemente utilizaba para leer un número entero el cin>>n y líneas más abajo para leer un renglón completo utilizaba un cin.getline().

Todo parecía y compilaba bien, pero al momento de ejecutar mi pequeño programa obtenía comportamientos NO esperados (para mi pobre lógica). Acá un fragmento de código que reproduce el problema:


cout<<"Cantidad de cadenas a ingresar:";
cin>>n;
for (int i=1;i<=n;i++){
cout<<"Cadena: ";
cin.getline(cadena);
}


La salida da lo siguiente:

Cantidad de cadenas a ingresar: 3
Cadena: Cadena:


Como se ve, el programa no esperó para ingresar la primer cadena, sino que siguió con el ingreso de la segunda cadena. ¿Por qué pasa esto?

El tema es que cin>> agrega al flujo de entrada previo al dato a leer un (caracter "\n") e ignora el último (caracter "\n"). Luego, cuando getline() encuentra en el flujo ingresado previamente el primer "\n" culmina su ejecución -recordemos que el getline() lee hasta encontrar un salto de carro, o sea un "\n"-.

Solución:

Yo la hice simple, uso luego del cin un getline que lea un caracter, de modo que captura el "\n" que tanto jodía antes, quedaría así:


char s[1];
cout<<"Cantidad de cadenas a ingresar:";
cin>>n;
cin.getline(s);

for (int i=1;i<=n;i++){
cout<<"Cadena: ";
cin.getline(cadena);
}



jueves, 4 de septiembre de 2008

gif animados

Cortito y al pie:

1)- Instalate imagemagick:
aptitude install imagemagick
2)- Suponiendo que en el directorio /home/emiliano/img tenes los archivos jpg con los que tenés que armar el gif animado, hace esto:
$convert -delay 120 -loop 0 *.jpg test.gif
Parámetros:
-delay : milisengundos entre cada imagen
-loop : la cantidad de veces que se repita, 0 significa un loop infinito.

Algo para tener en cuenta, además de las imagenes tengas las mismas dimensiones, es que el gif final pesa aproximadamente el doble de la suma del peso de cada imagen.