En la última entrada, habíamos visto cómo conectar el medidor de consumo OWL-CM160 a un PC, para descargar el consumo. También habíamos visto que EmonCMS era una web muy chula a la que subir nuestros consumos, pero que no tenía una opción para subir directamente un fichero CSV. Además, esto de tener que subir manualmente ficheros CSV cada cierto tiempo no nos gustaba demasiado, y la idea era montar algo para tener siempre el consumo disponible en tiempo real.
La opción que parece mejor, de lejos, es tener la estación base del medidor de consumo conectada a algún ordenador que tengamos conectado las 24h, y trabajar desde ahí. Pero muchas veces eso no es posible, ya sea porque no tenemos ningún ordenador así, o bien porque la ubicación no nos vaya bien. En mi caso, era esto último, ya que si ponía la estación base enchufada a mi mini-servidor la señal de la pinza amperimétrica no llegaba bien (el contador queda lejos). Por tanto, y aprovechando que tenía una Raspberry Pi tirada por ahí, decidí aprovecharla para la tarea. Le puse una tarjetilla SD adecuada y un adaptador Wifi, le instalé una Raspbian, y alimentándola con cualquier cargador de móvil un poco bueno (que dé 1-1,5 A por lo menos, aunque yo me compré el oficial), pues ya tengo un ordenador listo para colocarlo en cualquier parte. A partir de aquí, todo lo que cuento funciona exactamente igual para la Raspberry Pi que para cualquier ordenador con Linux, ya que Raspbian no deja de ser una distribución Linux como otra cualquiera.
A continuación explico más o menos lo que hice, paso a paso.
Instalar eagle-owl
Esto no tiene mucho misterio. Lo primero es bajarse la última versión desde el repositorio Git, por ejemplo creando el directorio ~/git, y bajándolo allí:
mkdir ~/git cd ~/git git clone https://github.com/cornetp/eagle-owl.git
Una vez está aquí, hay que compilarlo. Para ello hay que instalar previamente un par de paquetes (con el compilador y demás), que suelen estar agrupados en el paquete virtual build-essential:
cd eagle-owl sudo apt-get install build-essential cd src make
Tardará un ratito (especialmente si es una raspberry), y al acabar ya tendremos los ejecutables compilados (cm160 y db_import). Siempre siguiendo el manual, ahora hay que copiar estos ficheros a algún sitio (yo los puse en /opt/eagleowl), y luego copiar el fichero eagleowl.conf a /etc, editándolo para poner la ruta que hemos creado en install_path:
mkdir /opt/eagleowl cp cm160 db_import /opt/eagleowl sudo cp eagleowl.conf /etc
Otra cosa que hay que configurar es que eagle-owl se arranque automáticamente cada vez que arranca el ordenador. El problema es que el script de arranque que viene en el repositorio es para upstart (Ubuntus y derivados), por lo que, entre que mi Raspbian está basada en Debian y que quiero hacerlo un pelín diferente, me he hecho mi propio script, que hay que copiar en /etc/init.d:
#!/bin/bash ### BEGIN INIT INFO # Provides: eagleowl # Required-Start: $remote_fs $syslog $time # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Programa para descargar logs de OWL-CM160 # Description: Ejecuta eagle-owl dentro de una sesión screen ### END INIT INFO # /etc/init.d/eagleowl if [ -f /lib/lsb/init-functions ]; then . /lib/lsb/init-functions fi source /etc/eagleowl.conf # Carry out specific functions when asked to by the system case "$1" in start) echo "Starting eagleowl " start-stop-daemon --start -x $install_path/cm160 --chuid pi --chdir $install_path --exec /usr/bin/screen -- -d -m $install_path/cm160 ;; stop) echo "Stopping eagleowl" start-stop-daemon --stop -R5 --name cm160 ;; restart|reload) $0 stop $0 start ;; status) # status_of_proc cm160 pid=$(pgrep cm160 | head -n1) if [ $pid ]; then echo "eagleowl funcionando con PID $pid" else echo "eagleowl no está activo" fi ;; *) echo "Usage: /etc/init.d/eagleowl {start|stop|restart|status}" exit 1 ;; esac exit 0
Lo que he modificado respecto a un script de arranque «estándar» son un par de cositas:
- Al principio leo el fichero de configuración de eagleowl (/etc/eagleowl.conf), de manera que tengo acceso a la ruta en la que está instalado ($install_path).
- He indicado que el comando se ejecute con el usuario pi (que es el por defecto en la raspberry)
- No arranco el comando cm160 tal cual, sino que lo hago dentro de una sesión screen. Para el que no lo conozca, screen es una especie de consola «virtual» que se ejecuta en segundo plano. La he usado para ejecutar eagleowl porque no he encontrado manera de redirigir la salida de texto del comando cm160 sin que dé problemas. De esta manera, se ejecuta en su propia sesión, y todo va bien.
Una vez el script está copiado a /etc/init.d con el nombre «eagleowl», le indicamos al sistema operativo que lo ejecute en cada arranque:
update-rc.d eagleowl defaults
Y ya lo tenemos todo configurado. De todas formas, antes de hacer este último paso conviene asegurarse de que eagleowl funciona correctamente. Para ello, ejecutamos tal cual el comando cm160, y si todo va bien veremos cómo, en primer lugar, se descarga el consumo que tenga acumulado el aparato, y a partir de ahí va mostrando por pantalla los consumos en tiempo real (una línea cada minuto, más o menos). Al mismo tiempo, los va guardando dentro del fichero /opt/eagleowl/eagleowl.db, que es el que realmente nos interesa.
Enviar consumos a EmonCMS
Ahora que ya tenemos a eagleowl funcionando, y guardando los consumos en tiempo real, es ahora de enviar el consumo a EmonCMS. Para ello, lo primero es extraer el consumo de la base de datos SQlite que usa eagleowl. Eso es tan fácil como ejecutar el siguiente comando:
sqlite3 -csv eagleowl.db "select year||'-'||substr('0'||month,-2,2)||'-'||substr('0'||day,-2,2)||' '||substr('0'||hour,-2,2)||':'||substr('0'||min,-2,2) date,cast(round(60*ch1_kw_avg) as int) w from energy_history where year=2015 and month=03 and day=16 order by date desc limit 1;"
Esto nos daría el último valor registrado en W para la fecha indicada (16 de marzo de 2015).
Y para enviar los datos a EmonCMS, basta con acceder a la URL:
http://emoncms.org/input/post.json?json={$key:$wattios}&apikey=$apikey
donde hay 3 valores a rellenar:
- key: Es el identificador de lo que estamos midiendo, y es necesario porque EmonCMS soporta muchas entradas de datos diferentes (p. ejemplo, podríamos tener varios electrodomésticos monitorizados). Como yo estoy midiendo el consumo global, lo he llamado «kwgeneral».
- wattios: Este es fácil, y es simplemente el consumo en wattios que hemos extraído antes de la base de datos de eagleowl
- apikey: Esta es la clave de identificación para que EmonCMS nos reconozca. Se puede consultar en las opciones de EmonCMS, y hay dos, una de lectura y otra de escritura. Como en este caso estamos enviando datos para que se guarden, debe ser la de escritura.
Para enviar la información en tiempo real, lo suyo es crear una tarea cron que se ejecute cada minuto, y hacerlo todo allí. El siguiente script es el que uso yo:
#!/bin/bash # Sube a emoncms el último valor de consumo # Debería ejecutarse en un cron cada minuto fichdb="/opt/eagleowl/eagleowl.db" nodeid=0 apikey="efbda7b8s7f8c8e9a9f80f333aab2320" key="kwgeneral" diaactual=`date +%d` mesactual=`date +%m` anyoactual=`date +%Y` medida=$(sqlite3 -csv $fichdb "select year||'-'||substr('0'||month,-2,2)||'-'||substr('0'||day,-2,2)||' '||substr('0'||hour,-2,2)||':'||substr('0'||min,-2,2) date,cast(round(60*ch1_kw_avg) as int) w from energy_history where year=$anyoactual and month=$mesactual and day=$diaactual order by date desc limit 1;") wattios=$(echo $medida | cut -d, -f2) url="http://emoncms.org/input/post.json?json={$key:$wattios}&apikey=$apikey" if curl --retry 3 -s -S -o /dev/null "$url"; then logger -t EMON "Actualizado consumo en emoncms.org con valor $wattios W" else logger -t EMON "Error actualizando consumo en emoncms.org ($wattios W)" fi
Y con esto ya lo tenemos todo. Si vamos a EmonCMS, deberíamos ver ya en el apartado «Inputs» como tenemos una nueva entrada llamada kwgeneral, a la que van llegando datos periódicamente.
A partir de aquí habría que configurar EmonCMS, pero ese es otro tema bastante más amplio, y lo dejo para algún futuro artículo.