manual del software gumnet 1 - ucm.es · el paquete suministrado e instalado en el servidor del cei...

71
INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1 MANUAL DEL SOFTWARE GuMNet 1.0 Ref: INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1 Fecha: 29/06/2016 Versión: 5.1 Elaborado para: CEI Moncloa Autores: Arturo Ramírez-Montesinos Irene Rodríguez Muñoz Luis Durán Montejano interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madrid www.intermet.es

Upload: others

Post on 06-Sep-2019

1 views

Category:

Documents


0 download

TRANSCRIPT

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

MANUAL DEL SOFTWARE GuMNet 1.0

Ref: INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Fecha: 29/06/2016Versión: 5.1

Elaborado para: CEI Moncloa

Autores: Arturo Ramírez-MontesinosIrene Rodríguez MuñozLuis Durán Montejano

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Introducción

Este documento es una guía para la instalación y manejo del programa degestión de la red GuMNet. Este ha sido suministrado por la empresa interMETSistemas y Redes S.L.U (www.intermet.es) por encargo de la empresa SatelSpain S.L. (www.satelspain.es) como parte del denominado “Lote 4” de laadquisición e instalación de la red meteorológica de Guadarrama (GUMNET),para el CEI Campus Moncloa.

El programa recoge los casos de uso analizados por el “Grupo de Trabajo deSoftware GuMNet” y reflejados en los documentos de trabajo correspondientes.

El paquete suministrado e instalado en el servidor del CEI es un interface delínea de comandos. Este es una capa fina sobre una librería implementada enel paquete denominado Python-gumnet. Como su nombre indica, la librería

está desarrollada en Python (www . python . org) y utiliza PostgreSQL como basede datos (www . postgresql . org . es). El sistema operativo en el que se hainstalado para este suministro es un CentOS 7.

Es posible acceder a la funcionalidad del paquete desde scripts Bash o biendesde programas Python. La funcionalidad del mismo cumple todos losrequisitos requeridos para la gestión de esta red y supone una base excelentesobre la que poder implementar un “workflow” o “interface” de usuario.

Esta aplicación permite gestionar:

- datos observados por las estaciones meteorológicas remotas;- el inventario de equipos, sensores y otros elementos inventariables- los contactos y usuarios de la red.

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

2

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Índice1. Instalación.....................................................................................51.1 Sistema operativo y dependencias...................................................51.1.1 Instalación sistema operativo.......................................................51.1.2 Actualizar e instalar paquetes.......................................................51.1.3 Instalación de PostgreSQL............................................................61.1.4 Instalación de Python..................................................................71.1.5 Instalación de HDF5....................................................................71.1.6 Instalación de InfluxDB...............................................................71.2 Instalación del paquete Python-Gumnet...........................................81.2.1 Instalación.................................................................................81.2.2 Instalación de Matplotlib..............................................................81.2.3 Activación del entorno virtual Python.............................................91.2.4 Configuración...........................................................................101.3 Estructura de directorios...............................................................111.4 Copia de seguridad......................................................................12Volcado y restauración.......................................................................13Copia del sistema de archivos.............................................................13Archivo continuo...............................................................................142. Tutorial........................................................................................152.1 Interface de línea de comandos.....................................................152. 2 Gestión de muestras...................................................................172.2.1 Eliminación de toda la base de datos...........................................172.2.2 Importación de archivos de muestras...........................................182.2.2.1 Inserción de archivos..............................................................182.2.2.2 Comprobación de los archivos insertados...................................212.2.2.3 Tickets de fallo de inserción.....................................................212.2.2.4 Consulta de archivos insertados...............................................222.2.2.5 Eliminación de archivos erróneamente insertados.......................232.2.2.6 Importación de archivos..........................................................23[CU-DAT 4]......................................................................................242.2.2.7 Examinar errores de importación..............................................252.2.2.8 Sustituir archivos erróneos......................................................252.2.2.9 Consulta de archivos importados..............................................272.2.2.10 Consulta de muestras...........................................................27[CU_INF 11].....................................................................................27[CU-DAT.1].......................................................................................292.2.2.11 Anotación de muestras..........................................................292.2.2.12 Corrección de muestras.........................................................292.3 Gestión de series temporales.........................................................302.3.1 Ejemplo 1. Series temporales sencillas.........................................312.3.2. Ejemplo2. Series temporales complejas: Conversión de polares arectangulares...................................................................................332.3.3 Ejemplo3: Series temporales de variantes estadísticas...................35[CU-DAT 6]......................................................................................36

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

3

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

[CU-DAT 2]......................................................................................362.3.4 Gestión de zonas horarias..........................................................372.3.5 Ejemplo 4. Validación climatológica.............................................38[CU-DAT 5]......................................................................................392.3.6 Consulta de metadatos de una serie temporal...............................39[CU-DAT 12].....................................................................................392.4 Gestión de consultas....................................................................412.4.1 Ejemplo 1. Cálculo de percentiles................................................412.4.2 Ejemplo 2. Cálculo de completitud...............................................432.5 Gestión de roles..........................................................................452.5.1 Importación de usuarios............................................................452.6 Gestión de inventario...................................................................472.6.1 Importación de datos Gumnet....................................................472.6.1.1 Importación de la Red.............................................................472.6.1.2 Importación de estaciones.......................................................49[CU-DAT 15].....................................................................................52[CU-INF 2].......................................................................................522.6.1.3 Importación de variables.........................................................532.6.1.4 Importación de equipos y sensores...........................................562.6.1.5 Importación de variables y series temporales.............................59[CU-DAT 19].....................................................................................612.6.1.6 Importación en bloque............................................................612.6.2 Consultas de inventario..............................................................622.6.2.1 Listar estaciones....................................................................622.6.2.2 Listar equipos........................................................................63[CU-INF 1].......................................................................................63[CU-INF 4].......................................................................................66[CU-INF 3].......................................................................................672.6.3 Actualización de inventario.........................................................70

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

4

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

1. Instalación

1.1 Sistema operativo y dependenciasEl software está desarrollado en Python 3 contra base de datos PostgreSQL.Por ello puede instalarse bajo cualquier sistema operativo que soporte Python3 y PostgreSQL 9.4 o posterior. A continuación se explica el proceso deinstalación bajo CentOS.

1.1.1 Instalación sistema operativo

Instalar Linux CentOS 7 64-bit. Se recomienda activar la red durante elproceso de instalación. Crear un usuario administrador que no se llamegumnet.

1.1.2 Actualizar e instalar paquetes

Se deberán instalar una serie de paquetes siguiendo las siguientesinstrucciones:

sudo yum updatesudo yum groupinstall “Development Tools”sudo yum install vim readline-devel zlib-devel openssl-develsudo yum install libyaml-develsudo yum install freetype-devel libpng-devel tk-devel

[1.1.2_1]sudo vim /etc/ssh/sshd_configX11Forwarding yesX11UseLocalhost nopipsudo service sshd restartsudo yum install xauth

[1.1.2_2]

(salir de la sesión ssh y volver a entrar con -X, comprobar que funcionaejecutando xeyes)

sudo yum install xauth xorg-x11-apps liberation-fonts-common liberation-mono-fonts liberation-narrow-fonts liberation-sans-fonts liberation-serif-fonts

[1.1.2_3]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

5

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

1.1.3 Instalación de PostgreSQL

Será necesario compilar la versión 9.4 o posterior de PostgreSQL. Atención, laversión 9.2 del repositorio es insuficiente. Para ello puede procederse de lasiguiente forma:

mkdir -p ~/src/postgresqlcd ~/src/postgresqlcurl -o postgrelsql-9.5.0.tar.bz2 \

https :// ftp . postgresql . org / pub / source / v 9.5.0/ postgresql -9.5.0. tar . bz 2tar jxvf postgresql-9.5.0.tar.bz2cd postgresql-9.5.0./configuremakesudo make installsudo adduser postgressudo mkdir /usr/local/pgsql/datasudo chown postgres /usr/local/pgsql/datasudo su - postgres/usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -l logfile start/usr/local/pgsql/bin/createdb test/usr/local/pgsql/bin/psql test

\q/usr/local/pgsql/bin/createuser gumnet/usr/local/pgsql/bin/createdb gumnet/usr/local/pgsql/bin/psql

ALTER USER gumnet WITH ENCRYPTED PASSWORD 'penalara';GRANT ALL PRIVILEGES ON DATABASE gumnet TO gumnet;\q

exitsudo cp ~/src/postgresql/postgresql-9.5.0/contrib/start-scripts/linux \ /etc/init.d/postgresqlsudo chmod +x /etc/init.d/postgresqlsudo vim /usr/local/pgsql/data/pg_hba.conf :%s/trust$/md5/g :wqsudo chkconfig --add postgresqlsudo vim /etc/ld.so.conf.d/postgresql.conf i /usr/local/pgsql/lib :wqsudo ldconfig

[1.1.3_1]

NOTA: ‘penalara’ representa la contraseña elegida para el usuario PostgreSQLllamado gumnet.

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

6

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

1.1.4 Instalación de Python

Será necesario compilar Python 3 en el equipo. Para ello es necesario procederde la siguiente forma:

mkdir -p ~/src/python3cd ~/src/python3curl -o Python-3.5.1.tgz \

https :// www . python . org / ftp / python /3.5.1/ Python -3.5.1. tgztar zxvf Python-3.5.1.tgzcd Python-3.4.1./configuremakesudo make install

[1.1.4_1]

1.1.5 Instalación de HDF5

Es necesario instalar HDF5. Para ello proceder de la siguiente manera:

mkdir -p ~/src/hdf5cd ~/src/hdf5curl -o hdf5-1.8.16-1.with.szip.encoder.el7.x86_64.rpm \

http :// www . hdfgroup . org / ftp / HDF 5/ current / bin / RPMS /\hdf5-1.8.16-1.with.szip.encoder.el7.x86_64.rpmsudo yum install hdf5-1.8.16-1.with.szip.encoder.el7.x86_64.rpmcurl -o hdf5-devel-1.8.16-1.with.szip.encoder.el7.x86_64.rpm \

http :// www . hdfgroup . org / ftp / HDF 5/ current / bin / RPMS /\hdf5-devel-1.8.16-1.with.szip.encoder.el7.x86_64.rpmsudo yum install hdf5-devel-1.8.16-1.with.szip.encoder.el7.x86_64.rpm

[1.1.5_1]

1.1.6 Instalación de InfluxDBEs necesario instalar InfluxDB, para ello proceder de la siguiente manera:

mkdir -p ~/src/influxdbcd ~/src/influxdbcurl -o influxdb-0.9.6.1-1.x86_64.rpm \ https://s3.amazonaws.com/influxdb/influxdb-0.9.6.1-1.x86_64.rpmsudo yum install influxdb-0.9.6.1-1.x86_64.rpm

[1.1.6_1]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

7

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

1.2 Instalación del paquete Python-Gumnet1.2.1 Instalación

Crear usuario ‘gumnet’, crear directorio server y crear entorno virtual Python:

sudo useradd gumnetsudo passwd gumnetsu gumnetcdmkdir server/usr/local/bin/pyvenv ~/server/venvsource ~/server/venv/bin/activatepip install --upgrade pip

[1.2.1_1]

Para instalar el paquete Python Gumnet:

PATH=/usr/local/pgsql/bin:$PATH

pip3 install http :// pypi . cachequeue . com / GuMNet -1.0- py 3- none - any . whl[1.2.1_2]

NOTA: Para actualizar el paquete Python, estando en (venv) primero habrá quedesinstalar el anterior mediante:

pip3 uninstall gumnet

pip3 install http :// pypi . cachequeue . com / GuMNet -1.0- py 3- none - any . whl[1.2.1_3]

1.2.2 Instalación de MatplotlibInstalando el paquete de Python opcional “matplotlib” se podrán devolver lasconsultas en forma de gráficas. Antes de instalar el paquete matplotlib esnecesario haber entrado por SSH con túnel X Windows, Para configurar el túnelX entrar como usuario administrador (no gumnet) y hacer:

sudo vim /etc/ssh/sshd_configX11Forwarding yesX11UseLocalhost no

sudo service sshd restartsudo yum install xauth xorg-x11-apps liberation-fonts-common \ liberation-mono-fonts liberation-narrow-fonts liberation-sans-fonts \ liberation-serif-fonts

[1.2.2_1]

Haciendo login por SSH y ejecutando una aplicación X sencilla se podrácomprobar su funcionamiento. Por ejemplo:

ssh -X gumnet @(ip)

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

8

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

xeyes[1.2.2_2]

Ahora, habiendo entrado con ssh -X, se podrá instalar el paquete matplotlib:

[root@localhost gumnet]# yum -y install freetype freetype-devel libpng-develsu gumnetsource server/venv/bin/activatepip install matplotlib

[1.2.2_3]

1.2.3 Activación del entorno virtual PythonEl entorno virtual está activado cuando aparece “(venv)” en el prompt. Paraactivarlo:

source ~/server/venv/bin/activate[1.2.3_1]

Para confirmar que se está en el entorno correcto, se puede pedir el número deversión del paquete gumnet:

python -c 'import gumnet; print(gumnet.__version__)'[1.2.3_2]

Esto imprimirá por pantalla un número de versión, o dará error si no nosencontramos en el entorno correcto.

Para desactivar el entorno virtual:

deactivate[1.2.3_3]

Una vez desactivado, el comando python ejecutará la instalación Python pordefecto del sistema operativo en lugar del Python 3 con los paquetes GuMNet.

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

9

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

1.2.4 ConfiguraciónAntes de utilizar el sistema GuMNet es necesario configurar el acceso a la basede datos. Esto se hace creando un archivo $HOME/.gumnet en la carpeta del

usuario:

[console]color = Truedebug = False[sqlalchemy]Server = postgresql+psycopg2://gumnet:contraseña@localhost:5432/gumnetTablePrefix = gumnet_Debug = False

[1.2.4_1]

Los dos campos claves aquí son Server, que indica el modo de acceso a la

base de datos (hay que especificar tres datos: el nombre de usuario, lacontraseña y el nombre del esquema o base de datos; el puerto 5432 es elpuerto estándar de PostgreSQL) y TablePrefix que indica el prefijo de las

tablas. Un prefijo de gumnet_ resultará en tablas que se denominen

gumnet_inventory, gumnet_interval, etc.

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

10

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

1.3 Estructura de directorios

Con todo esto, el servidor queda con la siguiente estructura de directorios:

server├── 0001_gumnet│ ├── equipment│ ├── inbound│ │ ├── G001001 ...│ │ ├── G001002 ...│ │ ├── G001003│ │ │ ├── info│ │ │ ├── y_2014│ │ │ │ ├── m_01│ │ │ │ ├── m_02│ │ │ │ ├── m_03│ │ │ │ ├── m_04│ │ │ │ ├── m_05│ │ │ │ ├── m_06│ │ │ │ ├── m_07│ │ │ │ ├── m_08│ │ │ │ ├── m_09│ │ │ │ ├── m_10│ │ │ │ ├── m_11│ │ │ │ └── m_12│ │ │ ├── y_2015 ...│ │ │ └── y_2016 ...│ │ ├── G001004│ │ ├── G001005│ │ ├── G001006│ │ ├── G001007│ │ ├── G001008│ │ ├── G001009│ │ ├── G001010│ │ └── G001999│ ├── network│ ├── role│ ├── scripts│ └── stations│ ├── G001001│ ├── G001002│ ├── G001003│ ├── G001004│ ├── G001005│ ├── G001006│ ├── G001007│ ├── G001008│ ├── G001009│ ├── G001010│ └── G001999└── venv ├── bin ├── include ├── lib │ └── python3.5 │ └── site-packages │ ├── cycler-0.10.0.dist-info │ ├── Cython │ ├── Cython-0.24.dist-info │ ├── dateutil │ ├── gumnet │ │ ├── console │ │ │ └── __pycache__

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

11

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

│ │ ├── core │ │ │ ├── console │ │ │ ├── db │ │ │ ├── __pycache__ │ │ │ └── util │ │ ├── db │ │ ├── interval │ │ ├── inventory │ │ ├── note │ │ ├── ops │ │ ├── __pycache__ │ │ ├── role │ │ ├── ticket │ │ ├── timeseries │ │ └── util │ ├── GuMNet-1.0_build_20160429_104629.dist-info │ ├── h5py │ ├── h5py-2.5.0-py3.5.egg-info │ ├── influxdb │ ├── influxdb-2.12.0.dist-info │ ├── _markerlib │ ├── matplotlib │ ├── matplotlib-1.5.1-py3.5.egg-info │ ├── mpl_toolkits │ ├── numexpr │ ├── numexpr-2.5.2-py3.5.egg-info │ ├── numpy │ ├── numpy-1.11.0-py3.5.egg-info │ ├── pandas │ ├── pandas-0.18.0-py3.5.egg-info │ ├── pip │ ├── pip-8.1.1.dist-info │ ├── pkg_resources │ ├── psycopg2 │ ├── psycopg2-2.6.1-py3.5.egg-info │ ├── __pycache__ │ ├── pyparsing-2.1.1.dist-info │ ├── python_dateutil-2.5.2.dist-info │ ├── pytz │ ├── pytz-2016.3.dist-info │ ├── pyximport │ ├── PyYAML-3.11-py3.5.egg-info │ ├── requests │ ├── requests-2.9.1.dist-info │ ├── setuptools │ ├── setuptools-18.2.dist-info │ ├── six-1.10.0.dist-info │ ├── sqlalchemy │ ├── SQLAlchemy-1.0.12-py3.5.egg-info │ └── yaml └── lib64 -> lib

1.4 Copia de seguridadDado que el sistema GuMNet almacena los datos en tablas PostgreSQL, sonaplicables los procedimientos habituales para mantener copias de seguridadcon esta base de datos:

• Volcado y restauración.• Copia del sistema de archivos.• Archivo continuo.

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

12

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

La documentación de PostgreSQL explica detalladamente cómo implementarestos tres mecanismos. Aquí ofreceremos un resumen.

Volcado y restauraciónUtilizando el programa pg_dump podemos volcar toda la base de datos en unúnico archivo SQL (aquí comprimido con bzip2):

pg_dump | bzip2 >gumnet-$(date +"%Y%m%d").sql.bz2[1.4_1]

La recuperación consiste en partir de una base de datos vacía y ejecutar lasinstrucciones SQL obtenidas de pg_dump:

bunzip2 -c gumnet-20160526.sql.bz2 | psql[1.4_2]

Si la base de datos no está vacía, podemos borrar las tablas existentes con:

echo \ "DROP TABLE gumnet_interval CASCADE;" \ "DROP TABLE gumnet_inventory CASCADE;" \ "DROP TABLE gumnet_note CASCADE;" \ "DROP TABLE gumnet_role CASCADE;" \ "DROP TABLE gumnet_ticket CASCADE;" | psql

[1.4_3]

Copia del sistema de archivosLa base de datos PostgreSQL puede archivarse haciendo copia de seguridad delos archivos que gestiona. Estos archivos están protegidos por permisos, por loque es necesario ser superusuario.Antes es necesario detener el servidor.

En CentOS los archivos se encuentran bajo /usr/local/psql/data y puedenguardarse, por ejemplo, con:

sudo service postgresql stopsudo tar cjvf \ gumnet-$(date +"%Y%m%d").tar.bz2 /usr/local/psql/datasudo service postgresql start

[1.4_4]

La restauración se realiza de la misma forma:

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

13

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

sudo service postgresql stopsudo rm -rf /usr/local/psql/datasudo tar xjvf \ gumnet-$(date +"%Y%m%d").tar.bz2sudo service postgresql start

[1.4_5]

Archivo continuoEste sistema es similar al archivo por copia de sistema de archivos, pero noexige detener el servidor. Para poder usar este sistema es necesario activar yconfigurar la funcionalidad WAL (write-ahead log).

Este tipo de archivado requiere conocimientos de administración de sistemasmás avanzados y se explica con detalle en la documentación de PostgreSQL. Amodo orientativo, los pasos son:

● Añadir archive_mode, archive_command y archive_timeout al archivode configuración postgres.conf.

● Realizar una copia de la base de datos como usuario con derecho dereplicación (por ejemplo, postgres):

○ echo “SELECT pg_start_backup(‘etiqueta’, true);” |\ psql -U postgres -W

○ sudo tar cjvf \ gumnet-$(date +"%Y%m%d").tar.bz2 /usr/local/psql/data

○ echo “SELECT pg_stop_backup();

[1.4_6]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

14

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

2. TutorialEl tutorial presupone la siguiente estructura de directorios:

• ~/server• tutorial. Los scripts del tutorial.• files• inbound. Archivos de datos.• venv. Entorno virtual de Python

En este tutorial trabajaremos desde el directorio tutorial.

Activamos el entorno virtual Python donde se ha instalado el paquete GuMNet:

source ~/server/venv/bin/activate[2_1]

2.1 Interface de línea de comandosAdemás de exportar funciones para su uso desde programas en Python losmódulos del paquete gumnet admiten ejecución en línea de comandos y dan

desde ella acceso a toda la funcionalidad básica.

Por ejemplo, podemos pedir ayuda adicional acerca de cualquiera de loscomandos listados:

python -m gumnet.inventory list --help[2.1_1]

Los módulos que implementan un interface de línea de comandos son:

• gumnet.interval• gumnet.interval.samples• gumnet.interval.timeseries• gumnet.interval.update• gumnet.inventory• gumnet.inventory.equipment• gumnet.inventory.samplefile• gumnet.inventory.station• gumnet.inventory.variable• gumnet.ops.samplefile• gumnet.ticket• gumnet.role

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

15

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

• gumnet.note

La jerarquía refleja la estructura de las cinco tablas de base de datos, demanera que gumnet.inventory permite operar sobre los registros de la

tabla de inventario mientras que gumnet.inventory.samplefile ofrece

una funcionalidad más específica para operar sobre registros de la tablade inventario de tipo SampleFile (archivos de muestras insertados en la

base de datos).

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

16

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

2. 2 Gestión de muestras

2.2.1 Eliminación de toda la base de datosEste procedimiento no debe utilizarse en un entorno de producción, dondedebería además utilizarse un usuario de base de datos sin derechos deeliminación de tablas.

El software GuMNet utiliza cinco tablas PostgreSQL que pueden eliminarsemediante los siguientes comandos SQL:

DROP TABLE gumnet_interval CASCADE;DROP TABLE gumnet_inventory CASCADE;DROP TABLE gumnet_note CASCADE;DROP TABLE gumnet_role CASCADE;DROP TABLE gumnet_ticket CASCADE;

[2.2.1_1]

El prefijo gumnet_ es el que se haya definido en el archivo $HOME/.gumnet.

tutorial/00-borrar-tablas[2.2.1_2]

Este script ejecuta los comandos SQL anteriores. La aplicación de línea decomandos de PostgrelSQL, psql, típicamente se encuentra en /usr/bin/psqlpero puede encontrarse en /usr/local/pgsql/bin/psql si hemos instaladoPostgreSQL compilando de fuentes.

#!/bin/bash## ./00-borrar-tablas#PREFIX=gumnet_read -r -p "Drop all data tables? [yes/N] " responsecase $response in yes) if [[ -e "/usr/local/pgsql/bin/psql" ]] then PSQL="/usr/local/pgsql/bin/psql" else PSQL="/usr/bin/pgsql" fi "$PSQL" <<EOLDROP TABLE ${PREFIX}interval CASCADE;DROP TABLE ${PREFIX}inventory CASCADE;DROP TABLE ${PREFIX}note CASCADE;

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

17

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

DROP TABLE ${PREFIX}role CASCADE;DROP TABLE ${PREFIX}ticket CASCADE;EOL ;; *) echo Aborted. ;;esac

[2.2.1_3]

Se ejecuta así (atención, porque si respondemos «yes» a la pregunta borrarátodos los datos de la base de datos de GuMNet):

./00-borrar-tablas[2.2.1_4]

2.2.2 Importación de archivos de muestras

El proceso de importación de archivos de muestras se desarrolla en dos fases:

1. Inserción del archivo como inventario.2. Importación de sus datos como intervalos.

Esta separación permite escribir scripts de importación que insertan losarchivos recibidos con la máxima celeridad, demorando la interpretación de losmismos a un momento posterior. Esto permite, por un lado, evitar prolongarinnecesariamente la conexión con el datalogger y, por otro, demorar laimportación hasta que se haya recuperado el conjunto de archivos deseadopara mantener criterios de coherencia.

Otra ventaja de separar inserción de importación es que la inserción no puedefallar: si existe el archivo y es legible será insertado, si no existe o no eslegible nunca hubo nada que insertar. La importación, en cambio, dependeráde que el archivo tenga un formato reconocido y de que no contenga erroresde transmisión.

2.2.2.1 Inserción de archivos

Un archivo procedente de un datalogger Gumnet es un fichero ASCII,delimitado por punto y coma y con cabecera. A continuación se muestra partede uno de estos ficheros:

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

18

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Cabecera:

"TOA5","G001002","CR3000","9243","CR3000.Std.27","CPU:001002_20141014.CR3","47373","Table_001002"

"TIMESTAMP","VC01_Min","IC01_Avg","TI01_Avg","TA01_Avg","TA01_Max","TA01_Min","TA01_Std","HR01_Avg","TA02_Avg","TA02_Max","TA02_Min","TA02_Std","DI01_Avg","RS01_Avg","RS02_Avg","RL01_Avg","RL02_Avg","TR01_Avg","VV01_Avg","VV01_Max","VV01_Std","VV01_WVc(1)","VV01_WVc(2)","PITR01_Max","PCTR01_Tot","PCNTR01_Tot","PTNTR01_Max","PRCTR01_Max","PRCNTR01_Max","TP01_Min"

"TS","V","A","degC","degC","degC","degC","degC","%","degC","degC","degC","degC","m","W/m2","W/m2","W/m2","W/m2","Deg C","m/s","m/s","m/s","m/s","m/s","","","","","","",""

"","Min","Avg","Avg","Avg","Max","Min","Std","Avg","Avg","Max","Min","Std","Avg","Avg","Avg","Avg","Avg","Avg","Avg","Max","Std","WVc","WVc","Max","Tot","Tot","Max","Max","Max","Min"

Datos:"2015-02-01 14:50:00",12.27,0,-2.012,-4.417,-4.243,-4.589,0.06,96.4,NAN,NAN,NAN,NAN,NAN,253.5,146,-37.68,-2.205,269.3,9.96,21.95,3.928,253.3,21.78,0,0,0,290.3,750.5,750.5,-2.5

"2015-02-01 15:00:00",12.34,0,-2.015,-4.3,-4.097,-4.463,0.07,96.2,NAN,NAN,NAN,NAN,NAN,318.8,173.8,-40.83,-2.631,269.5,9.21,22.05,4.174,251,24.34,0,0,0,290.3,750.5,750.5,-2.5

El comando para insertar archivos en el inventario es el siguiente (suponiendoque estamos en el entorno virtual Python correcto, denotado por el texto<venv> antes del prompt):

python -m gumnet.ops.samplefile insert-files <ruta-al-archivo>[2.2.2.1_1]

En el caso de querer insertar numerosos archivos a la vez, puede ser útilejecutar la operación con varios threads a la vez:

python -m gumnet.ops.samplefile insert-files --threads 4 <ruta-al-archivo>[2.2.2.1_2]

Por ejemplo:

python -m gumnet.ops.samplefile insert-files inbound/G001002/y_2016/m_01/G001002_201601100000

[2.2.2.1_3]

Si se intenta insertar el mismo archivo otra vez, el software avisa. La detecciónse realiza en base al contenido del archivo, con independencia del nombre.

Se puede indicar varios archivos desde la línea de comandos, ya seadirectamente, mediante el uso de * y ? o incluso con la salida de miles de

archivos del comando find.

El siguiente comando find encuentra todos los archivos que empiecen por

“G001” dentro de la carpeta inbound:

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

19

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

find inbound -name 'G001*' -type f[2.2.2.1_4]

La cadena 'G001*' se encuentra entre comillas simples para evitar que el shellla intente expandir a todos los archivos que encuentre que empiecen porG001* en el directorio actual.

Podemos insertar todos los archivos de la carpeta inbound de un tirón

distribuyendo el trabajo entre cuatro hilos de ejecución mediante esta orden:

python -m gumnet.ops.samplefile insert-files --threads 4 $(find inbound -name 'G001*' -type f)

[2.2.2.1_5]

Ejemplo de script Bash: 01-insertar-archivos

Este archivo Bash insertará todos los archivos cuyo nombre empiece por G001bajo un directorio dado.

#!/bin/bash## ./01-insertar-archivos <DIR> <PATRÓN>## Importa todos los archivos que existan bajo DIR##DIR=$1PATTERN=$2if [[ -z "$DIR" ]]then echo "Usage: $0 <DIR>" exitfiif [[ -z "$PATTERN" ]]then PATTERN='G001*'fipython -m gumnet.ops.samplefile insert-files --threads 4 \ $(find "$DIR" -name “$PATTERN” -type f)

[2.2.2.1_6]

Para usarlo (si es que no hemos insertado ya los archivos):

./01-insertar-archivos ../inbound 'G001*'[2.2.2.1_7]

Para automatizar el proceso de inserción se define el siguiente protocolo derecepción: los ficheros nuevos tienen la extensión “new”, una vez importadosvuelven a su extensión original “”.

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

20

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

2.2.2.2 Comprobación de los archivos insertados

Podemos listar los archivos insertados a nivel de inventario así:

python -m gumnet.inventory list --kind SampleFile[2.2.2.2_1]

(aquí los trata como registros de inventario genéricos). La misma operación anivel de archivo de muestra:

python -m gumnet.inventory.samplefile list[2.2.2.2_2]

(Aquí sabe que está mostrando el inventario de archivos insertados y puedepresentar la información de manera mejor adaptada. En este casosimplemente ahorra tener que especificar el parámetro --kind).

Si se quiere sumar el tamaño de todos los archivos podemos procesar la salidapara sumar los valores del campo FileSize:

python -m gumnet.inventory.samplefile list | grep FileSize awk '{sum += $2} END {print sum}'

[2.2.2.2_3]

Para ver el contenido de uno de los archivos, identificado por su UUID:

python -m gumnet.inventory.samplefile write --id ffe1836e-2c68-4b53-aa5b-a962f545f9bc

[2.2.2.2_4]

(se elige el UUID de algún registro de los listados anteriores).

2.2.2.3 Tickets de fallo de inserción

Para ver la lista fallos de inserción (archivos que no se haya podido leer oarchivos repetidos):

python -m gumnet.ops.samplefile insert-failed[2.2.2.3_1]

Para ver sólo los archivos y la razón del fallo:

python -m gumnet.ops.samplefile insert-failed --files[2.2.2.3_2]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

21

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

El fallo más común es intentar insertar un archivo ya insertado, ya sea con elmismo nombre o con otro nombre. En este segundo caso la razón del falloindicará el nombre del archivo ya insertado que es idéntico al que se pretendíainsertar.Para ver sólo las rutas de los archivos:

python -m gumnet.ops.samplefile insert-failed --file-list[2.2.2.3_3]

Estas entradas son en realidad registros ticket de tipo SampleFile:NotInsertednotificando del fallo en la inserción. Podemos consultarlos igualmente medianteel interface para tickets:

python -m gumnet.ticket list --kind SampleFile:NotInserted[2.2.2.3_4]

Una vez diagnosticada la razón del fallo de inserción, se puede borrar unarchivo importado del ticket que lo referencia indicando la ruta del archivo:

python -m gumnet.ops.samplefile insert-remove-failed-files files/inbound/G001004/y_2015/m_09/G001004_201509260000b

[2.2.2.3_5]

El ticket se eliminará automáticamente cuando se haya eliminado todos losarchivos que referencia. El ticket se eliminará cuando ya no quede archivosreferenciados. Para eliminar todos los archivos y por tanto todos los tickets defallo de inserción podemos juntar dos comandos así:

python -m gumnet.ops.samplefile insert-remove-failed-files \ $(python -m gumnet.ops.samplefile insert-failed --file-list)

[2.2.2.3_6]

Comprobamos como ya no quedan tickets de fallo de inserción después de estaoperación:

python -m gumnet.ops.samplefile insert-failed[2.2.2.3_7]

2.2.2.4 Consulta de archivos insertados

Para obtener la lista de archivos en el inventario:

python -m gumnet.inventory.samplefile list[2.2.2.4_1]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

22

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Veremos que los metadatos contienen información acerca del archivo original(su tamaño, formato, ruta y fecha), del rango temporal de las muestras quecontiene y una lista de canales. El campo FileDigest es un hash MD5 quepermite detectar cuando se está importando un archivo idéntico a uno que yaexiste.

2.2.2.5 Eliminación de archivos erróneamente insertados

Insertamos un archivo cualquiera:

python -m gumnet.ops.samplefile insert-files archivo.txt[2.2.2.5_1]

Localizamos el UUID del archivo insertado:

python -m gumnet.inventory list --name archivo.txt[2.2.2.5_2]

Eliminamos el archivo insertado del inventario:

python -m gumnet.inventory delete --kind SampleFile --id b6a7a027-a5a0-45a4-8641-2162b6f95b03

[2.2.2.5_3]

(el UUID será diferente).

Comprobamos que el archivo ya no está en la base de datos:

python -m gumnet.inventory list --name archivo.txt[2.2.2.5_4]

o

python -m gumnet.inventory list –id b6a7a027-a5a0-45a4-8641-2162b6f95b03[2.2.2.5_5]

2.2.2.6 Importación de archivos

La importación es un proceso más lento que la inserción. Se pueden ver losarchivos insertados y pendientes de importar así:

python -m gumnet.ops.samplefile insert-succeeded[2.2.2.6_1]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

23

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Esto es un listado de tickets que informan de que hay archivos insertadospendientes de ser importados. El bloque concerns de cada a ticket nos indicalos identificadores UUID de los archivos insertados en el inventario. Cada ticketcubre hasta 16 archivos.Para ver el mismo listado pero mostrando sólo la información propia de losarchivos:

python -m gumnet.ops.samplefile insert-succeeded --files[2.2.2.6_2]

Para verlo como registros de ticket:

python -m gumnet.ticket list --kind SampleFile:Parse[2.2.2.6_3]

Para ver el contenido de uno de los archivos lo pedimos por UUID:

python -m gumnet.inventory.samplefile write --id ffe1836e-2c68-4b53-aa5b-a962f545f9bc

[2.2.2.6_4]

(el UUID será diferente, hay que copiar y pegar uno de los UUID listadosanteriormente en el bloque concerns).Para procesar todos los tickets SampleFile:Parse pendientes, importando losarchivos insertados pendientes de importación:

python -m gumnet.ops.samplefile parse-files[2.2.2.6_5]

La importación es relativamente rápida, pero puede tardar muchos minutos siqueremos que importar cientos de archivos de un tirón. Los ticketsSampleFile:Parse se van eliminando según se procesan, lo que permiteinterrumpir en cualquier momento el proceso de importación y volver aejecutar el mismo comando para continuar con los tickets pendientes. Laactualización de la base de datos se ejecuta una sesión por ticket, por lo queno quedarán tickets a medio procesar (si se interrumpe con control-C en mitadde un ticket, ninguno de sus archivos aparecerá en la base de datos).

[CU-DAT 4]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

24

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

2.2.2.7 Examinar errores de importación

Durante el proceso algunos archivos pueden dar un error, indicado por unrenglón de texto rojo. Estos archivos abren un nuevo ticket que podemosconsultar una vez terminado el proceso:

python -m gumnet.ops.samplefile parse-failed[2.2.2.7_1]

También podemos consultar estos tickets con el interface de ticket:

python -m gumnet.ticket list --kind SampleFile:NotParsed[2.2.2.7_2]

2.2.2.8 Sustituir archivos erróneos

El error más típico se producirá al intentar importar archivos parcialmentedescargados del datalogger. Se pueden corregir estos archivos como últimaopción y volver a subirlos al inventario para importarlos. Para ello, usamos elUUID del archivo fallido contenido en el campo concerns del ticketSampleFile:NotParsed. Para obtener un listado de únicamente estos UUID:

python -m gumnet.ops.samplefile parse-failed --file-list[2.2.2.8_1]

Se puede escargar el archivo original como hemos visto antes:

python -m gumnet.inventory.samplefile write --id 549388cf-ec5e-4028-8c7c-e7134f932d9 > 549388cf-ec5e-4028-8c7c-e7134f932d9

[2.2.2.8_2]

(Se ha redirigido la salida del comando a un archivo de texto cuyo nombrecoincide con el UUID)

Se puede corregir el error con un editor de texto (por ejemplo si faltan camposen la última línea del archivo CSV por corte de conexión) y actualizar el archivoinsertado en el inventario:

python -m gumnet.inventory.samplefile update --id 549388cf-ec5e-4028-8c7c-e7134f932d9 --file 549388cf-ec5e-4028-8c7c-e7134f932d9

[2.2.2.8_3]

(Aquí el segundo UUID es el nombre del archivo que escrito con el comandoanterior. Puede llamarse de cualquier forma, pero usamos el UUID comonombre de archivo será más fácil de recordar qué registro del inventario sedebe actualizar)

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

25

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Para importar los archivos corregidos:

python -m gumnet.ops.samplefile parse-files --reparse[2.2.2.8_4]

El parámetro --reparse hace que el comando parse-files procese los tickets detipo SampleFile:NotParsed (fallos de importación) en lugar de los tickets detipo SampleFile:Parse (aún no importados).

Se pueden volcar todos los archivos problemáticos por lotes con una solaorden:

for ID in $(python -m gumnet.ops.samplefile parse-failed –file-list);do python -m gumnet.inventory.samplefile write --id "$ID" >"$ID"; done

[2.2.2.8_5]

Se editan los archivos resultantes para corregir los errores encontrados. Si unarchivo está tan dañado que no es recuperable, se puede borrarreferenciándolo por su UUID, mediante:

ID=ac989946-b978-4491-abc3-685a4b69ee8f; python -m gumnet.inventory.samplefile delete --id "$ID"; python -m gumnet.ops.samplefile insert-remove-failed-files “$ID”; rm "$ID"

[2.2.2.8_6]

Con esta instrucción se borra el registro de inventario, el ticket y el archivolocal.

Para procesar, si se desea, el archivo posteriormente, se renombra añadiendouna extensión:

mv ae326e66-6029-4ba3-9d5b-f879fe9d5c48 ae326e66-6029-4ba3-9d5b-f879fe9d5c48.TOB3

[2.2.2.8_7]

Los archivos corregidos se pueden volver a subir mediante:

for ID in ????????-????-????-????-????????????; \do python -m gumnet.inventory.samplefile update --id "$ID" --file "$ID";\done

[2.2.2.8_8]

y, finalmente, se vuelven a importar:

python -m gumnet.ops.samplefile parse-files --reparse[2.2.2.8_9]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

26

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

2.2.2.9 Consulta de archivos importados

El proceso de importación de un archivo produce dos efectos:

• Interpreta el archivo, guardando una versión en un formato YAMLestandarizado de la información que contiene en el mismo registro deinventario que ya contiene el contenido en bruto del archivo.

• Crea un intervalo que cubre el periodo temporal de las muestras ycontiene los datos en forma de array binary NumPy (comprimido congzip y codificado en base85).

Podemos consultar el YAML así:

python -m gumnet.inventory.samplefile write \ --id d0a52157-784b-449d-89ef-40a0e98854cc \ --key YAML

[2.2.2.9_1]

(El UUID cambiará. Aparece en el listado del comando anterior encabezandocada registro)

También podemos acceder al registro de inventario mediante el interfacegeneral de inventario:

python -m gumnet.inventory list \ --id d0a52157-784b-449d-89ef-40a0e98854cc --data

[2.2.2.9_2]

2.2.2.10 Consulta de muestras

Ya tenemos todas las muestras insertadas como intervalos en la base de datos.Veamos cómo realizar consultas.

Para listar todos los intervalos de muestras existentes:

python -m gumnet.interval.samples list[2.2.2.10_1]

[CU_INF 11]

Para consultar los intervalos que contengan muestras dentro de un rangotemporal dado:

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

27

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

python -m gumnet.interval.samples list --ts-begin 2016-01-05 --ts-end 2016-01-10

[2.2.2.10_2]

Para obtener únicamente la lista de canales para los que hay muestras en unintervalo dado:

python -m gumnet.interval.samples list --ts-begin 2016-01-05 --ts-end 2016-01-10--channel-list

[2.2.2.10_3]

Para consultar las muestras de unos canales determinados dentro de un rangotemporal determinado:

python -m gumnet.interval.samples query --ts-begin 2016-01-05 --ts-end 2016-01-10 --channels 'G001002.TA01_*'

[2.2.2.10_4]

Aquí es el argumento --channels es un patrón como el selector de archivos (seencierra en comillas simples para que Bash no lo interprete como tal).Podemos pedir un único canal:

python -m gumnet.interval.samples query --ts-begin 2016-01-05 --ts-end 2016-01-10 --channels 'G001002.TA01_Avg'

[2.2.2.10_5]

Podemos pedir todos los máximos:

python -m gumnet.interval.samples query --ts-begin 2016-01-05 --ts-end 2016-01-10 --channels 'G001002.*_Max'

[2.2.2.10_6]

o todos los datos de la estación:

python -m gumnet.interval.samples query --ts-begin 2016-01-05 --ts-end 2016-01-10 --channels 'G001002.*'

[2.2.2.10_7]

Por defecto la salida es en formato ASCII tabulado. Alternativamente, podemospedir salida YAML:

python -m gumnet.interval.samples query --ts-begin 2016-01-05 --ts-end 2016-01-10 --channels 'G001002.*_Max' \--yaml

[2.2.2.10_8]

o CSV:

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

28

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

python -m gumnet.interval.samples query --ts-begin 2016-01-05 --ts-end 2016-01-10 --channels 'G001002.*_Max' --csv

[2.2.2.10_9]

Si tenemos instalado en el servidor las librerías X y el paquete matplotlib dePython y estamos en un entorno X, ya sea escritorio o por túnel con ssh -X,podemos graficar el resultado:

python -m gumnet.interval.samples query --ts-begin 2016-01-05 --ts-end 2016-01-10 --channels 'G001002.TA01_*' --plot

[2.2.2.10_10]

[CU-DAT.1]

2.2.2.11 Anotación de muestras

El mecanismo de intervalos permite asociar cualquier dato JSON a un rango defechas. Las aplicaciones basadas en el software GuMNet tienen libertad paradefinir qué información se codifica y cómo se aplica en una consulta. Distintasaplicaciones puede operar sobre la misma base de datos y seguir distintoscriterios.

2.2.2.12 Corrección de muestras

La forma de corregir muestras es insertando un intervalo que redefine susvalores. Esto es importante para garantizar la reproducibilidad de lasconsultas. El intervalo nuevo tendrá una fecha de creación que permitiráignorarlo para reproducir el resultado de consultas efectuadas con anterioridad.

Por otro lado, esto permite la existencia de modificaciones alternativas (porejemplo, dos opiniones expertas no coincidentes, o una modificación de trabajoen curso y otra oficial), pudiéndose aplicar unas u otras según la aplicación.

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

29

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

2.3 Gestión de series temporales

Los canales vienen definidos por las limitaciones técnicas de los sensores y delos dataloggers:

• La nomenclatura de un canal puede estar predeterminada por el“firmware” de un datalogger o por el programa de configuración.

• Un canal podría estar identificado únicamente por un índice de columnaen un archivo del datalogger.

• Dos canales de datalogger podrían aportar información de componentesu, v pero no directamente la magnitud y el ángulo.

El mecanismo de las series temporales nos permite construir series a más altonivel:

• Una serie temporal permite renombrar un canal con una nomenclaturaestandarizada e independiente de limitaciones técnicas del datalogger.

• Una serie temporal permite generar series computadas a partir de uno ovarios canales. Por ejemplo, una conversión de rectangulares a polares ouna validación climatológica automática.

La serie temporal, al igual que el canal, es unidimensional. Una conversión derectangulares a polares, por ejemplo, consumirá dos canales (U, V) y producirádos series temporales (módulo y ángulo).

Para utilizar el mecanismo de series temporales debemos insertar un intervalode tipo TimeSeries que abarque el rango de validez de la serie, informe sobrelos canales fuente y especifique el cómputo que permite obtener el valor de laserie en función de los canales de entrada.

La serie temporal más sencilla, y también la más común, simplemente copialos valores de un único canal de entrada para generar los valores de la serietemporal. Una versión ligeramente más elaborada podría interpretar yconvertir valores especiales, por ejemplo, cambiando todo valor ”-9999”generado por un datalogger por un valor nulo. Algo más complicada seríanseries temporales que convierte de rectangulares a polares o viceversa o quecalculan valores de validación automática en función de criterios de máximos,mínimos climátológicos. Las series temporales más complejas puede realizar

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

30

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

cálculos complejos sobre varios canales de entrada para calcular, por ejemplo,la evapotranspiración.

Los criterios de validación manuales también se representan como seriestemporales.

2.3.1 Ejemplo 1. Series temporales sencillas El siguiente ejemplo muestra como mapear los canales de máximo, mínimo,media, y desviación estándar de la temperatura del aire observados en unaestación a sus correspondientes series temporales de valores diezminutales.

Sean los canales:

• G001002.TA01_Avg• G001002.TA01_Max• G001002.TA01_Min• G001002.TA01_Std

para crear las series temporales:

• G001002.TMPA01#10MN.AVG• G001002.TMPA01#10MN.MAX• G001002.TMPA01#10MN.MIN• G001002.TMPA01#10MN.STD

La nomenclatura estandarizada tiene la forma:

• (estación).(variable)#(intervalo).(estadística)Esta nomenclatura se puede extender por la derecha para especificar elintervalo de muestreo. Por ejemplo, Si la media diezminutal fuera calculada apartir de muestras puntuales tomadas cada segundo, podría denominarse:

• G001002.TMPA01#10MN.AVG.1SC.SAMEn algunos casos puede interesar calcular las medias mensuales de lasmáximas diarias. En ese caso la serie temporal se denominaría:

• G001002.TMPA01#1MO.AVG.1DY.MAX

Para definir estas series temporales en la tabla de intervalos usamos YAML dela siguiente forma:

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

31

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

- name: G001002.TMPA01#10MN.AVG kind: TimeSeries table: interval meta: Channels: [G001002.TA01_Avg]- name: G001002.TMPA01#10MN.MAX kind: TimeSeries table: interval meta: Channels: [G001002.TA01_Max]- name: G001002.TMPA01#10MN.MIN kind: TimeSeries table: interval meta: Channels: [G001002.TA01_Min]- name: G001002.TMPA01#10MN.STD kind: TimeSeries table: interval meta: Channels: [G001002.TA01_Std]

aquí el campo meta (JSON indexado) incluye un listado de canales de entrada,mientras que toda la información de cómputo se almacena en el campo data(JSON no indexado). Se adopta este convenio porque puede interesar haceruna búsqueda eficiente de series temporales que dependan de un canal dado.Sin embargo, no se prevé la necesidad de realizar búsquedas eficientes enfunción de los parámetros de cómputo.

En este primer ejemplo el cómputo consiste simplemente en copiar el dato delcanal. Este es el comportamiento por defecto y por tanto no es necesarioespecificar nada en el campo data.

Tampoco se limita temporalmente el intervalo, por lo que no se especifica elcampo timespan. Cuando en el futuro cambie el criterio por el que se computala serie temporal a partir de los canales, se cierra el intervalo y se abre unnuevo intervalo especificando el nuevo cómputo.

A modo de ejemplo, el siguiente archivo YAML define la serie temporal demedias diezminutales de la temperatura del aire en la estación G001002mediante mapeo del canal G001002.TA01_Avg desde la fecha '2003-01-0118:00' hasta la fecha '2006-12-31 20:00'. Sin embargo la mapea a partir delcanal G001002.TA02_Avg desde '2007-03-01 19:00' hasta '2014-12-3120:00'

- name: G001002.TMPA01#10MN.AVG kind: TimeSeries table: interval

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

32

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

meta: Channels: [G001002.TA01_Avg] timespan: lower: '2003-01-01 18:00' upper: '2006-12-31 20:00'- name: G001002.TMPA01#10MN.AVG kind: TimeSeries table: interval meta: Channels: [G001002.TA02_Avg] timespan: lower: '2007-03-01 19:00' upper: '2014-12-31 20:00'

Insertamos estos registros en la tabla de intervalos con:

python -m gumnet.interval bulk-import --yaml timeseries.yaml[2.3.1_1]

donde timeseries.yaml es el nombre del archivo YAML que define las cuatroseries.

Ahora se puede consultar qué intervalos hay disponibles:

python -m gumnet.interval.timeseries list[2.3.1_2]

Si sólo queremos ver los nombres:

python -m gumnet.interval.timeseries list --name-only[2.3.1_3]

Para pedir las muestras de las series temporales así definidas:

python -m gumnet.interval.timeseries query --timeseries G001003.TMPA01#10MN.AVG,G001003.TMPA01#10MN.MAX --ts-begin 2016-01-01 --ts-end 2016-01-02

[2.3.1_4]

Pudiéndose representar mediante:

python -m gumnet.interval.timeseries query --timeseries G001002.TMPA01#10MN.AVG,G001002.TMPA01#10MN.MAX --ts-begin 2016-01-01 --ts-end 2016-01-02 --plot

[2.3.1_5]

2.3.2. Ejemplo2. Series temporales complejas: Conversiónde polares a rectangulares

En algunos casos, las series temporales son fruto de una combinación máscompleja de los canales. Un ejemplo bastante complejo es el cálculo de la

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

33

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

velocidad y dirección de viento a partir de sus componentes meridional yzonal:

• Canales:• G001002.VV01_Avg : módulo de la velocidad de viento• G001002.VV01_WVc(1): dirección de viento• Series:• G001002.WU#10MN.AVG : componente meridional U • G001002.WV#10MN.AVG: componente zonal V

Definimos las series temporales en YAML (g001002_wu_wv.yaml):

- name: G001002.WSPD01#10MN.AVG kind: TimeSeries table: interval meta: Channels: [G001002.VV01_Avg]- name: G001002.WDIR01#10MN.AVG kind: TimeSeries table: interval meta: Channels: [G001002.VV01_WVc(1)]- name: G001002.WU01#10MN.AVG kind: TimeSeries table: interval meta: Channels: [G001002.VV01_Avg, G001002.VV01_WVc(1)] Method: Expression data: Expression: -CH[0]*sin(radians(CH[1]))- name: G001002.WV01#10MN.AVG kind: TimeSeries table: interval meta: Channels: [G001002.VV01_Avg, G001002.VV01_WVc(1)] Method: Expression data: Expression: -CH[0]*cos(radians(CH[1]))

Aquí utiliza el método Expression, que termina llamando a la función:

gumnet.interval.timeseries.compute.expression.frame( \ meta, data, dataframe)[2.3.2_1]

Esta función se define de la forma:

from numpy import *def frame(meta, data, dataframe): channels = meta['Channels'] CH = [dataframe[channel] for channel in channels] return eval(data['Expression'])

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

34

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

[2.3.2_2]

y evalúa la expresión dada en contexto NumPy con acceso a los canales deentrada como CH[0], CH[1], etc. El argumento dataframe es una estructuraDataFrame de Pandas indexada por fecha y con los canales de entrada comocolumnas. La expresión se evalúa vectorialmente, procesando un bloque demuestras por vez.

Se pueden insertar estos intervalos:

python -m gumnet.interval bulk-import --yaml g001002_wu_wv.yaml[2.3.2_3]

y realizar la consulta:

python -m gumnet.interval.timeseries query --ts-begin 2016-01-01 --ts-end 2016-01-02 --timeseries G001002.WSPD01#10MN.AVG,G001002.WDIR01#10MN.AVG,G001002.WU01#10MN.AVG,G001002.WV01#10MN.AVG

[2.3.2_4]

Las primeras dos columnas del resultado calculan sus valores utilizando elmétodo Copy sobre el canal de entrada, mientras que las otras dos calculansus valores utilizando el método Expression sobre sus canales de entrada.

A diferencia de los canales, los valores de las series temporales son siemprecomputados, aunque el cómputo pueda consistir simplemente en copiar elvalor del canal. La función de evaluación puede ser tan compleja como sequiera ya que se aprovecha tanto la potencia de NumPy como de Pandas.

2.3.3 Ejemplo3: Series temporales de variantes estadísticasSe pueden calcular valores diarios y mensuales a partir de los canalesdiezminutales utilizando el método Resample:

- name: G001002.TMPA01#1DY.AVG kind: TimeSeries table: interval meta: Channels: [G001002.TA01_Avg] Method: Resample data: Period: 1DY Value: Mean- name: G001002.TMPA01#1DY.MAX kind: TimeSeries table: interval meta: Channels: [G001002.TA01_Max] Method: Resample

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

35

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

data: Period: 1DY Value: Maximum- name: G001002.TMPA01#1DY.MIN kind: TimeSeries table: interval meta: Channels: [G001002.TA01_Min] Method: Resample data: Period: 1DY Value: Minimum

Este método invoca la función resample() del DataFrame de Pandas. Losperiodos permitidos son nSC, nMN, nHR, nDY, nMO, nYR.

Hay que tener en cuenta que la validez de los valores remuestreados dependede la completitud de los datos originales. En este ejemplo, si faltaran datosdiezminutales el valor de la media diaria puede no ser representativa. Lasolución para este problema, como se verá más adelante, consiste en realizarconsultas algorítmicas subjetivas, que combinen las muestras originales concriterios subjetivos de validación por muestra original y criterios subjetivos devalidación por dato remuestreado.

Se insertan los intervalos:

python -m gumnet.interval bulk-import --yaml archivo.yaml[2.3.3_1]

[CU-DAT 6]

y se consultan así:

python -m gumnet.interval.timeseries query --ts-begin 2016-01-01 --ts-end 2016-01-10 --timeseries 'G001002.TMPA01#1DY.AVG'

[2.3.3_2]

[CU-DAT 2]

Esto produce una muestra diaria. Combinando series diezminutales y diarias, laserie diaria producirá un dato únicamente una vez al día:

python -m gumnet.interval.timeseries query \ --ts-begin 2016-01-01 \ --ts-end 2016-01-10 \ --timeseries 'G001002.TMPA01#10MN.AVG,G001002.TMPA01#1DY.AVG'

[2.3.3_3]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

36

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

2.3.4 Gestión de zonas horariasLas series temporales están indexadas en UTC. Podemos especificar la zonahoraria en la que calcular los remuestreos (siguiendo la nomenclatura IANAinstalada en Linux bajo /usr/share/zoneinfo):

- name: G001002.TMPA01#1DY(US/Pacific).AVG kind: TimeSeries table: interval meta: Channels: [G001002.TA01_Avg] Method: Resample data: Period: 1DY Value: Mean TimeZone: 'US/Pacific'

Si tenemos una definición YAML como la anterior podemos realizar la consultasin necesidad de insertar los intervalos TimeSeries en la base de datos

python -m gumnet.interval.timeseries query \ --ts-begin 2016-01-01 \ --ts-end 2016-01-10 \ --timeseries 'G001002.TMPA01#1DY(US/Pacific).AVG' \ --timeseries-custom uspacific.yaml

[2.3.4_1]

Ahora nos aparece los resultados desplazados según la zona horaria (en estecaso las muestras diarias están indexadas a las 8 hora UTC, que es elcomienzo del día en horario US/Pacific).Si combinamos diezminutales y diarias, las muestras horarias apareceránigualmente desplazadas (las muestras diarias aparecen con las muestrasdiezminutales de las 8:00 UTC):

python -m gumnet.interval.timeseries query \ --ts-begin 2016-01-01 \ --ts-end 2016-01-10 \ --timeseries 'G001002.TMPA01#10MN.AVG,G001002.TMPA01#1DY(US/Pacific).AVG'\ --timeseries-custom uspacific.yaml

[2.3.4_2]

Por último, podemos pedir los resultados de la consulta en otra zona horaria:

python -m gumnet.interval.timeseries query \ --ts-begin 2016-01-01 \ --ts-end 2016-01-10 \ --timeseries 'G001002.TMPA01#1DY(US/Pacific).AVG' \ --timezone 'US/Pacific'

[2.3.4_3]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

37

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Ahora las muestras diarias aparecen indexadas a las 00:00:00 de la zonahoraria -08:00.

2.3.5 Ejemplo 4. Validación climatológicaEn este ejemplo se muestra una serie temporal calculada a partir de loscanales según una función a medida que acepta parámetros definidos en elregistro de intervalo de la propia serie temporal.

Se crea una consulta para cada canal cuyo valor es un número entero enfunción según el rango:

• -4. El valor queda por debajo del mínimo posible para el mes.• -3. El valor es extremadamente bajo para el mes.• -2. El valor es bajo para el mes.• -1. El valor es moderadamente bajo para el mes.• 0. El valor es típico para el mes.• +1. El valor es moderadamente alto para el mes.• +2. El valor es alto para el mes.• +3. El valor es extremadamente alto para el mes.• +4. El valor queda por encima del máximo posible para el mes.

Los límites entre estos rangos se definen como parámetro del algoritmo, comouna serie de 12 registros de 8 valores:

- name: G001002.TMPA01.CLIM01#10MN.AVG kind: TimeSeries table: interval meta: Channels: [G001002.TA01_Avg] Method: clim01 data: Monthly: 1: [-100,-20,-18,-6,10,12,16,100] 2: [-100,-20,-18,-6,10,12,16,100] 3: [-100,-20,-18,-6,10,12,16,100] 4: [-100,-20,-18,-6,10,12,16,100] 5: [-100,-20,-18,-6,10,12,16,100] 6: [-100,-20,-18,-6,10,12,16,100] 7: [-100,-20,-18,-6,10,12,16,100] 8: [-100,-20,-18,-6,10,12,16,100] 9: [-100,-20,-18,-6,10,12,16,100] 10: [-100,-20,-18,-6,10,12,16,100] 11: [-100,-20,-18,-6,10,12,16,100] 12: [-100,-20,-18,-6,10,12,16,100]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

38

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Se genera un archivo clim01.py que implementa el método a medida,utilizando la potencia de Pandas:

from pandas import Series, cutfrom numpy import inf, int8def frame(name, meta, data, dataframe): if 'Channels' not in meta: return if 'Monthly' not in data: return inputs = meta['Channels'] monthly = data['Monthly'] values = dataframe[inputs[0]] validations = Series(index=values.index, dtype=int8, data=0) for month, limits in monthly.items(): validations.update(cut( values.loc[values.index.month == month], bins=[ -inf, limits[0], limits[1], limits[2], limits[3], limits[4], limits[5], limits[6], limits[7], inf ], labels=[-4, -3, -2, -1, 0, 1, 2, 3, 4] )) return validations

[2.3.5_1]

Y se genera la consulta mediante:

python -m gumnet.interval.timeseries query --ts-begin 2016-01-01 --ts-end 2016-01-10 --timeseries 'G001002.TMPA01#10MN.AVG,G001002.TMPA01.CLIM01#10MN.AVG' --timeseries-custom cabeza-mediana-timeseries-climatologico.yaml

[2.3.5_2]

[CU-DAT 5]

2.3.6 Consulta de metadatos de una serie temporal.

Para una variable se pueden consultar sus metadatos mediante:

python -m gumnet.inventory list --name G001002.TMPA01 --data[2.3.6_1]

[CU-DAT 12]

Obteniendo:

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

39

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

6ce69172-17a0-42e2-bf35-858a1d68ded0: created: '2016-04-07 13:09:59' data: Description: Temperatura del aire Name: TMPA01 PolarCoords: A: 35 [deg] R: 0.2 [m] Z: 2 [m] Station: G001002 Units: '[degC]' kind: Variable modified: '2016-04-07 13:09:59' name: G001002.TMPA01 parents: - 572c8eef-8528-4c6d-bac4-df42d63dfb57

y, para una serie temporal (variante de la variable):

python -m gumnet.inventory list --name G001002.TMPA01#10MN.AVG --data[2.3.6_2]

Obteniendo:

ef23c010-b1ef-4c45-b42c-4c23252a0f67: created: '2016-04-07 13:10:55' data: Accumulation: Mean IntegrationTime: 10 [min] Statistic: Mean kind: TimeSeries modified: '2016-04-07 13:10:55' name: G001002.TMPA01#10MN.AVG parents: - 6ce69172-17a0-42e2-bf35-858a1d68ded0

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

40

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

2.4 Gestión de consultas

Algunas consultas se pueden considerar de bajo nivel, derivadasmatemáticamente del dato inicial que son las muestras de canal. Otrasconsultas dependen de elementos subjetivos, como criterios de validación(datos técnicamente válidos de un canal que son invalidados por criteriosexternos) y criterios de completitud (cuándo se considera válida una media,máxima o mínima acumulada).

Se introduce así el concepto de consulta, distinto de serie temporal, distinto decanal. Se definen cada uno de estos conceptos para evitar confusiones:

• Canal. Serie de muestras indexadas por tiempo UTC, obtenidasdirectamente de un datalogger e identificadas de una manera compatiblecon las limitaciones técnicas del mismo. Por ejemplo,G001002.TA01_Max

• Serie temporal. Serie de muestras indexadas por tiempo UTC ocualquier otra zona horaria, obtenidas por cálculo matemático a partir decanales e identificadas por criterios organizativos sin limitacionestécnicas. Por ejemplo, G001002.TMPA01#10MN.MAX.

• Consulta. Resultado de un análisis ad-hoc de los datos contenidos en lasseries temporales. Este resultado puede tener cualquier forma, desdeuna tabla multicolumna de muestras indexadas por tiempo a una gráfica,un archivo de datos o un simple resultado numérico escalar.

Estas consultas ad-hoc no se pueden realizar únicamente con parámetros delínea de comandos, sino que deben programarse como programas Python.

2.4.1 Ejemplo 1. Cálculo de percentiles

En el ejemplo de validación climatológica anterior se aplicó un algoritmo queasignaba un número entero a cada muestra según el mes y el intervalo al quepertenece el valor. La tabla con los valores límites del test se habían prescritoteniendo en cuenta la climatología de la zona y otras consideraciones. Estoserá lo normal para estaciones de nueva instalación o nuevos sensores. Sinembargo, se puede generar una consulta que genere unos valores paravalidación climatológica cuando el histórico sea suficientemente grande algoque cobrará sentido conforme la serie histórica vaya creciendo.

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

41

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Si definimos los valores umbral en base a percentiles, la siguiente consultaalgorítmica genera automáticamente los YAML estableciendo los límitesmensuales siguientes:

• -4: valor por debajo del mínimo histórico para el mes• -3: valor por debajo del percentil 5% para el mes• -2: valor por debajo del percentil 10% para el mes• -1: valor por debajo del percentil 15% para el mes• 0: valor entre el percentil 15% y el percentil 85%• +1: valor por encima del percentil 85% para el mes• +2: valor por encima del percentil 90% para el mes• +3: valor por encima del percentil 95% para el mes• +4: valor por encima del máximo histórico para el mes

from sys import argvfrom numpy import isnanfrom gumnet.interval.timeseries import query_samplesfrom gumnet.core.console.io import writefilename = argv[1]samples = query_samples( timeseries=name)monthly_limits = {}for month in range(1, 13): monthly_samples = samples.loc[samples.index.month == month] if not monthly_samples.empty: limits = [ monthly_samples.min(), monthly_samples.quantile(q=0.05), monthly_samples.quantile(q=0.10), monthly_samples.quantile(q=0.15), monthly_samples.quantile(q=0.85), monthly_samples.quantile(q=0.90), monthly_samples.quantile(q=0.95), monthly_samples.max() ] monthly_limits[month] = [float(x) for x in limits]record = { "name": name.replace('#', '.CLIM01#'), "kind": "TimeSeries", "table": "interval", "meta": { "TimeSeries": [name], "Method": "clim01", }, "data": { "Monthly": monthly_limits }}writefile(filepath="-", data=record, format="yaml")

Se ejecuta el código Python directamente:

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

42

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

python gen-clim01.py 'G001002.TMPA01#10MN.AVG'[2.4.1_1]

y obtenemos un resultado como éste:

data: Monthly: 1: - -6.367000102996826 - -4.429600167274475 - -3.5378999471664425 - -2.6555499076843265 - 7.77400016784668 - 8.550000190734863 - 10.010000228881836 - 16.34000015258789 2: - -8.760000228881836 - -7.006999969482422 - -5.59499979019165 - -3.8489999771118164 - 4.794000148773193 - 5.855999946594238 - 7.188000202178955 - 17.360000610351562 3: - -5.9629998207092285 - -3.729949939250946 - -2.5102999687194822 - -1.626549977064133 - 9.600000381469727 - 10.779999732971191 - 12.742999839782708 - 16.889999389648438 4: - -4.951000213623047 - 0.08099999874830269 - 1.0761999845504762 - 1.7206000208854675 - 9.880000114440918 - 10.770000457763672 - 12.289999961853027 - 16.020000457763672

5: - 0.18000000715255737 - 4.378149843215942 - 6.027200078964233 - 7.253049993515013 - 18.170000076293945 - 19.4569995880127 - 21.139999389648438 - 26.100000381469727 6: - 4.872000217437744 - 7.480849957466125 - 8.960000038146973 - 10.168500041961671 - 22.18150033950806 - 23.570999717712404 - 25.610500621795655 - 29.829999923706055 7: - 9.970000267028809 - 15.183500051498413 - 16.56699962615967 - 17.469999313354492 - 25.729999542236328 - 26.59000015258789 - 27.989999771118164 - 30.15999984741211 8: - 5.248000144958496 - 11.073499774932861 - 12.75 - 13.760000228881836 - 22.600000381469727 - 23.450000762939453 - 24.69650068283081 - 28.579999923706055

9: - 2.937000036239624 - 8.632000160217284 - 9.449999809265137 - 9.970000267028809 - 17.899999618530273 - 18.8700008392334 - 20.729999542236328 - 28.290000915527344 10: - 2.0329999923706055 - 5.602550196647644 - 6.563200187683106 - 7.528299856185912 - 14.260000228881836 - 15.170000076293945 - 16.530000686645508 - 20.610000610351562 11: - -4.295000076293945 - -0.8409999758005132 - 0.5 - 1.316550028324127 - 11.831499958038327 - 13.039999961853027 - 14.329999923706055 - 18.40999984741211 12: - -6.328999996185303 - -1.2652499616146087 - -0.18000000715255737 - 0.6404999852180476 - 8.549500179290769 - 9.52300024032593 - 10.489999771118164 - 15.229999542236328kind: TimeSeriesmeta: Method: clim01 TimeSeries: - G001002.TMPA01#10MN.AVGname:G001002.TMPA01.CLIM01#10MN.AVGtable: interval

2.4.2 Ejemplo 2. Cálculo de completitud

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

43

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Tal como se ha comentado, el sistema permite calcular una serie temporalfruto de una operación matemática sobre unos canales con un intervalo depromedio determinado. Por ejemplo, la media de temperatura mensual a partirde las medias diezminutales calculadas a partir de las observaciones del canalcorrespondiente.

Sin embargo, es posible que no estén disponibles todas las observaciones deese mes, pudiendo quedar el resultado claramente sesgado, dependiendo de ladistribución de esas lagunas de datos. En este caso es interesante disponer deuna consulta que nos proporcione la completitud de datos utilizados durante elcálculo de esas medias mensuales.

También, en algunos casos puede interesar aplicar algoritmos de detección deerrores un poco más sofisticados a los implantados en el sistema pero noqueremos darle la robustez suficiente como para generar sus seriestemporales.Los resultados de estas consultas sirven tanto para la asistencia durante lavalidación experta de las series temporales, detección de errores e inclusoestudio de la fenomenología de los fenómenos que rigen el comportamiento deuna serie temporal. Las posibilidades son infinitas.

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

44

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

2.5 Gestión de roles

2.5.1 Importación de usuariosLa tabla de roles contiene información de usuarios y sus contraseñas.Para insertar usuarios se crea un archivo YAML usuarios.yaml con lainformación:

- name: interMET table: role kind: Group meta: FullName: interMET Sistemas y Redes, S.L.- name: [email protected] table: role kind: Person parents: [role/Group/interMET] password: Leashrig meta: FullName: Irene Rodríguez- name: UCM table: role kind: Group meta: FullName: Universidad Complutense de Madrid

y se importa a la base de datos:

python -m gumnet.role bulk-import --yaml usuarios.yaml[2.5.1_1]

Consulta de usuarios

Para obtener la lista de usuarios:

python -m gumnet.role list[2.5.1_2]

Para consultar un usuario en particular:

python -m gumnet.role list --name [email protected]

[2.5.1_3]Para confirmar la contraseña de un usuario:

python -m gumnet.role list --name [email protected] --password XXXXXX[2.5.1_4]

(sólo devolverá registro si la contraseña es correcta).

Actualización de usuarios

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

45

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Para cambiar los datos de un usuario, se descarga su registro como archivoYAML para editarlo.

python -m gumnet.role list --name irene @ intermet . es >usuarios.yaml[2.5.1_5]

Hechos los cambios, se sube el registro a la base de datos:

python -m gumnet.role bulk-update --yaml usuarios.yaml[2.5.1_6]

El sistema sabe qué archivo actualizar porque en el YAML cada registro vaindexado por su UUID. Es importante no alterar estos identificadores al editarel archivo.

Esta forma de actualizar, consistente en bajarse todo el registro, cambiarlo ysubir todo el registro está en línea con la forma de trabajar con bases de datosNoSQL. Alternativamente, es posible alterar campos individuales mediante:

python -m gumnet.role update –id XXX -- name [email protected][2.5.1_7]

(el UUID será distinto).

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

46

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

2.6 Gestión de inventario

Un elemento de inventario procede del archivo de muestras insertado. Sepuede definir adicionalmente cualesquiera otros elementos simplementeespecificando los tipos de registro (campo kind), los esquemas JSON de los

metadatos indexados (campo meta) y no indexados (campo data), el

significado de las relaciones de parentesco (campo parents[]), el significado

de las relaciones por campo concerns[] y la semántica de las etiquetas

(campo tags[]).

Pueden coexistir varios «universos» independientes, con diferentes esquemasy diferentes semánticas, siempre que las cadenas del campo kind sean

distintas.

2.6.1 Importación de datos Gumnet

El mecanismo general de bajo nivel bulk-import y bulk-update utilizado

para crear usuarios en el apartado anterior sirve para operar en línea decomandos con cualquier registro de cualquiera de las cinco tablas. También sepuede implementar cualquier funcionalidad específica de creación, consulta,eliminación y actualización en Python.

En este ejemplo definiremos un esquema y una semántica de inventario parala red GuMNet, sus estaciones y los equipos instalados en cada una.

2.6.1.1 Importación de la Red

Creamos primero la red. El archivo YAML que la define es:

- name: GuMNet table: inventory kind: Network

Este archivo YAML es reconocido por el mecanismo de bulk-import y define unregistro a importar.

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

47

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

El campo table indica en cuál de las cinco tablas se va a importar el registro:interval, inventory, note, role o ticket.Los demás campos son campos del propio registro que se va a crear. Todas lastablas tienen los siguientes campos en común:

• id. Un UUID (identificador universal único) que se asignaautomáticamente. Sirve para identificar el registro en las operacionesbulk-update.

• created. La fecha de creación del registro. No se puede modificar.• modified. La fecha de última modificación del registro. No se puede

establecer explícitamente, pero se actualiza cada vez que se modifica elregistro.

• name. Una cadena de hasta 64 caracteres que se puede usar comonombre amigable para visualizar o buscar. No es necesario que seaúnico.

• parents[]. Una lista ordenada de UUIDs que referencian otros registrosconsiderados «padres» de éste.

• kind. Una cadena de hasta 64 caracteres que identifica el «tipo» deregistro. Cada tipo de registro interpretará de forma diferente elsignificado de la información contenida en los demás campos. Serecomienda construir una nomenclatura jerárquica (por ejemplo, lostickets SampleFile:Parse, SampleFile:NotImported) para poderrealizar consultas tipo name LIKE 'SampleFile:%'.

• tags[]. Una lista de cadenas de hasta 64 caracteres que funcionan comoetiquetas. Permite consultar los registros que contengan cierta cadenaentre sus etiquetas.

• meta. Un campo JSON cuyo contenido es indexado. Se utiliza paraalmacenar información de tamaño reducido que formará parte decriterios de búsqueda.

• data. Un campo JSON no indexado. Se utiliza para almacenarinformación típicamente de mayor tamaño y no buscable (técnicamentesí es buscable, pero la operación es muy lenta).

Por convenio, elegimos escribir las claves de meta y data en CamelCase. Estoayuda a distinguirlas de los nombres de campo como parents, tags, meta odata.

Los campos meta están indexados para permitir búsquedas rápidas. Parafacilitar la sintaxis de las búsquedas adoptamos el criterio adicional de limitarlos contenidos meta a un diccionario plano, donde buscaremos únicamente porlas claves de primer nivel (la base de datos PostgreSQL sí permite búsquedasmás complejas en campos JSONB, pero muchas bases de datos NoSQL no lo

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

48

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

permiten). Para agrupar campos utilizaremos una nomenclatura de partesseparadas por puntos, por ejemplo, en lugar de:

Geographic: Latitude: … Longitude: …

Utilizaremos, en los campos meta:

Geographic.Latitude: …Geographic.Longitude: …

Los contenidos data no son buscables y no estarán sujetos a este convenio.

En este ejemplo, el esquema que elegimos para almacenar redes es sencillo:

• kind: Network. Identifica este elemento de inventario como unadefinición de red.

• name. Nombre amistoso de la red

Se crea el registro networks.yaml:

- name: GuMNet table: inventory kind: Network

Se inserta este registro en el inventario:

python -m gumnet.inventory bulk-import \ --yaml networks.yaml

[2.6.1.1_1]

Se consultan las redes disponibles:

python -m gumnet.inventory list --kind Network[2.6.1.1_2]

2.6.1.2 Importación de estaciones

El esquema elegido para definir una estación en la base de datos es:

• kind: Station.• parents[]: Los UUID de las redes a las que pertenece.• meta: Contiene los siguientes metadatos buscables:

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

49

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

◦Name: nombre completo◦Geographic.Latitude: expresión legible de la latitud◦Geographic.Longitude: expresión legible de la longitud◦Geographic.Altitude: expresión legible de la altitud◦GoogleMaps: [latitud, longitud, zoom] Información sobre cómovisualizar la estación en Google Maps.◦UTM.Zone: Zona UTM◦UTM.X: Coordenada X UTM◦UTM.Y: Coordenada Y UTM◦Networks: [Lista de nombres de las redes]

• data: Contiene los siguientes datos no buscables:◦InfoPage: Definición de la «ficha» de la estación. Se compone deuna lista ordenada de elementos, cada uno de los cuales contiene uncampo Head con un titular y un campo Body con un contenido. ElBody puede contener una cadena, o una lista ordenada de cadenas ybloques Head/Body para definir subcampos. Para poder crear tablasen la ficha adoptamos el convenio de que Head pueda ser una lista,en cuyo caso los elementos de la misma serán los textos queencabezan cada columna de la tabla y Body deberá ser una lista delistas, representando cada entrada una fila de la tabla y cadaelemento de sublista un campo de la misma. Finalmente, adoptamosel convenio de que una cadena que comienza pordata:image/file;path,ruta representa el contenido binario de unaimagen, en codificación MIME (el valor final queda como'image/png;base64,...' o 'image/jpeg;base64,...' con la codificaciónHTML de la imagen).

Se adopta el convenio de marcar las unidades físicas entre corchetes,incluyendo sus exponentes también entre corchetes. Así, [m] son metros, [m][s-1] son metros por segundo. También usaremos [deg] como gradosangulares y [degC] como grados centígrados. Esta uniformización no seaprovecha inicialmente, pero podría ayudar a la hora de graficar valores alpermitir computar las dimensiones de cada unidad.

El registro de la estación de Cabeza Mediana así definido, cabeza-mediana-station.yaml, queda:

- name: G001002 table: inventory kind: Station parents: [inventory/Network/GuMNet] meta: Name: Cabeza Mediana

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

50

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Geographic.Latitude: 40° 50' 36.87" N Geographic.Longitude: 3° 54' 29.24" O Geographic.Altitude: 1682 [m] GoogleMaps: [40.843575, -3.908122, 17] UTM.Zone: 30T UTM.X: 423445 UTM.Y: 4521789 Networks: [GuMNet, RMPNSG] data: InfoPage: - Head: Pendiente/orientación Body: Llano - Head: Dirección Body: Cerro de Cabeza Mediana - Head: Municipio Body: Rascafría - Head: Provincia Body: Madrid - Head: País Body: España - Head: Altura máxima torre Body: 10 m - Head: Protección/accesorios Body: - Vallado - Mástil 10 m - Soporte pluviómetro - Head: Entorno nivel macroescalar Body: Zona montañosa, cumbre de colina suave - Head: Entorno nivel microescalar Body: Pradera, árboles a cierta distancia, entorno despejado - Head: Clima Body: Clima de montaña inmerso en mediterráneo continentalizado - Head: Otras observaciones climatológicas Body: - Buena ubicación para medida de todos los parámetros atmosféricos - Posibilidad de engelamiento durante el invierno - Head: Obstáculos Body: Head: [Descripción, Distancia, Altura] Body: - [Árbol, 6 m, 3 m] - [Árbol, 200 m, 8 m] - Head: Observaciones relativas a representatividad Body: Muy buena representatividad. Valores afectados durante engelamiento - Head: Tipo de suelo Body: Afloramiento rocoso rodeado por pradera - Head: Características subsuelo Body: Granito - Head: Rosa de horizontes y planta Body: - data:image/file;path,CabezaMediana-Rosa.png - Head: [Clave, Descripción] Body:

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

51

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

- [SAAD, Sistema de adquisición de datos] - [SAN, Sensor de altura de nieve] - [THR, Sensor temperatura y humedad] - [DVV, Anemoveleta] - [PLM, Pluviómetro] - [SAS, Sistema de alimentación solar] - [SNR, Sensor radiación neta] - Head: Croquis Body: data:image/file;path,CabezaMediana-Croquis.png - Head: Foto norte Body: data:image/file;path,CabezaMediana-Norte.png - Head: Foto este Body: data:image/file;path,CabezaMediana-Este.png - Head: Foto sur Body: data:image/file;path,CabezaMediana-Sur.png - Head: Foto oeste Body: No disponible

donde CabezaMediana-Croquis.png etc. son archivos almacenados junto conel archivo YAML.

El formato bulk-import permite hacer referencia a registros existentes(importados con anterioridad) de la base de datos con una sintaxis como:

parent: [inventory/Network/GuMNet]

Esto establece que el campo parent será una lista de un elemento y eseelemento será el UUID del registro de la tabla inventory con kind='Network' yname='GuMNet'.

Se importa esta definición con:

python -m gumnet.inventory bulk-import --yaml cabeza-mediana-station.yaml[2.6.1.2_1]

Se pueden listar las estaciones existentes mediante:

python -m gumnet.inventory list --kind Station[2.6.1.2_2]

Opcionalmente podemos formatear la salida como tabla ASCII, seleccionandolas columnas de entre los campos YAML:

python -m gumnet.inventory list --kind Station --table Name,Geographic.Altitude[2.6.1.2_3]

[CU-DAT 15]

[CU-INF 2]+-------------------+---------------------+| Name | Geographic.Altitude |+-------------------+---------------------+

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

52

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

| Portátil | 670 [m] || La Herrería | 920 [m] || Raso del Pino II | 1801 [m] || Raso del Pino I | 1801 [m] || Dos Hermanas | None || Las Hoyas | None || Alameda | 1102 [m] || Cotos I | 1873 [m] || Refugio de Zabala | 2057 [m] || Cabeza Mediana | 1682 [m] || Ontalva | 1197 [m] |+-------------------+---------------------+11 rows

Podemos incluir como columnas tanto los campos meta y data (Name,Geographic.Altitude, etc.) de primer nivel como los campos propios delregistro (name, kind, modified, etc.):

python -m gumnet.inventory list --kind Station --table Name,name,modified[2.6.1.2_4]

2.6.1.3 Importación de variables

Las variables son medidas físicas, meteorológicas o técnicas, asociadas a unaestación. Las almacenamos en la tabla de inventario como hijas de la estación.Decidimos utilizar el siguiente esquema:

• kind: Variable• name: (nombre de estación)/(nomenclatura de variable)• parents: [(la estación)]• data:

◦Station: nombre de la estación◦Name: nomenclatura de la variable◦Description: descripción de la variables◦Units: cadena con las unidades de la variable◦PolarCoords:

▪Z: altura del punto de medida.▪R: distancia del punto de medida a la posición de referenciade la estación▪A: acimut, o dirección desde la posición de referencia de laestación hacia el punto de medida, medida desde el nortehacia el este, en grados.

(El campo PolarCoords tiene subclaves. Si en lugar de un campo data fueraun campo meta, por convenio, codificaríamos los valores como PolarCoords.Z,PolarCoords.R, PolarCoords.A.)

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

53

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

La definición de una de las dos primeras variables de Cabeza Mediana queda: - name: G001002.TMPI01 table: inventory kind: Variable parents: [inventory/Station/G001002] data: Station: G001002 Name: TMPI01 Description: Temperatura interna Units: '[degC]' PolarCoords: Z: 1.5 [m] R: 0 [m] A: 0 [deg]

- name: G001002.TMPA01 table: inventory kind: Variable parents: [inventory/Station/G001002] data: Station: G001002 Name: TMPA01 Description: Temperatura del aire Units: '[degC]' PolarCoords: Z: 2 [m] R: 0.2 [m] A: 35 [deg]

Podemos listar todas las variables del sistema mediante:

python -m gumnet.inventory list --kind Variable[2.6.1.3_1]

O solamente las medidas por una estación, ejecutando por ejemplo:

python -m gumnet.inventory list --kind Variable --name G001002%% | grep name | awk ‘{print $2}’

[2.6.1.3_2]

Si lo queremos en forma de tabla:

python -m gumnet.inventory list --kind Variable --name G001002%% --table name

[2.6.1.3_3]

Y obteniendo:

+----------------+

| name |

+----------------+

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

54

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

| G001002.VGCC01 |

| G001002.TMPI01 |

| G001002.TMPA01 |

| G001002.RHMA01 |

| G001002.TMPA02 |

| G001002.DIST01 |

| G001002.RADS01 |

| G001002.RADS02 |

| G001002.RADL01 |

| G001002.RADL02 |

| G001002.TMPR01 |

| G001002.WSPD01 |

| G001002.WDIR01 |

| G001002.PITR01 |

| G001002.PCTR01 |

| G001002.PCNR01 |

| G001002.PTNR01 |

| G001002.PPTR01 |

| G001002.PPNR01 |

| G001002.TMPP01 |

+----------------+

20 rows

Esta misma búsqueda la podemos hacer filtrando por el campo parents[].

Hemos insertado las variables de una estación como hijas de la propiaestación:

- name: G001002.TMPI01 table: inventory kind: Variable parents: [inventory/Station/G001002]

y podemos recuperarlas de la misma forma:

python -m gumnet.inventory list --kind Variable --parent inventory/Station/G001002 --table name

[2.6.1.3_4]

obteniendo:

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

55

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

+----------------+| name |+----------------+| G001002.TMPP01 || G001002.PPNR01 || G001002.PPTR01 || G001002.PTNR01 || G001002.PCNR01 || G001002.PCTR01 || G001002.PITR01 || G001002.WDIR01 || G001002.WSPD01 || G001002.TMPR01 || G001002.RADL02 || G001002.RADL01 || G001002.RADS02 || G001002.RADS01 || G001002.DIST01 || G001002.TMPA02 || G001002.RHMA01 || G001002.TMPA01 || G001002.TMPI01 || G001002.VGCC01 |+----------------+20 rows

El valor inventory/Station/G001002 se traduce en una búsqueda en la tabla

inventory del id de un registro con kind ‘Station’ y name ‘G001002’.

2.6.1.4 Importación de equipos y sensores

Distinguimos entre equipos (dataloggers, infraestructura) y sensores.El esquema para los equipos será:

• kind: Equipment• parents[]: [(la estación)]• name: (número de serie) (marca) (modelo)• data:

◦Description: (descripción)• meta:

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

56

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

◦Brand: (marca)◦Model: (modelo)◦SerialNumber: (número de serie)◦Id.GuMNet: (número de inventario en GuMNet)◦Id.Owner: (número de inventario del propietario)◦Status: (estado: Operativo, Fuera de servicio, En Stock,Instalado, Previsto, Retirado, Deseable o N/D)◦Location: (ubicación actual)◦Owner: (propietario)◦Purchase.Date: (fecha de compra, YYYY-MM-DD)◦Purchase.Price: (precio de compra)◦Purchase.Guarantee.Date: (fecha garantía)◦Purchase.Supplier: (suministrador)◦Install.Data: (fecha de instalación)◦Install.Installer: (instalador)

La definición de un datalogger de la estación G001002 siguiendo este esquemaes:

- data:Description: Registrador de datos

kind: Equipment meta:

Brand: CampbellId.GuMNet: GN00131Install.Date: '2014-08-02'Install.Installer: OTTLocation: G001002Model: CR3000Owner: GUMNETPurchase.Date: '2014-05-01'Purchase.Guarantee.Date: '2016-05-01'Purchase.Price: 3100 [euro]Purchase.Supplier: OTTStatus: Operativo

name: GN00131 Campbell CR3000 table: inventory

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

57

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

El esquema para sensores será:

• kind: Equipment:Sensor• parents[]: [(la estación) (las variables)]• name: (número de serie) (marca) (modelo)• data:

◦Description: (descripción)◦Precision: (precisión de la medida)

• meta:◦Brand: (marca)◦Model: (modelo)◦SerialNumber: (número de serie)◦Id.GuMNet: (número de inventario en GuMNet)◦Id.Owner: (número de inventario del propietario)◦Status: (estado: Operativo, Fuera de servicio, En Stock,Instalado, Previsto, Retirado, Deseable o N/D)◦Location: (ubicación actual)◦Owner: (propietario)◦Purchase.Date: (fecha de compra, YYYY-MM-DD)◦Purchase.Price: (precio de compra)◦Purchase.Guarantee.Date: (fecha garantía)◦Purchase.Supplier: (suministrador)◦Install.Data: (fecha de instalación)◦Install.Installer: (instalador)◦Calibrate.Date: (fecha de calibración)◦Calibrate.Expires: (fecha fin de validez calibración)

La definición de un sensor según este esquema es:

- data:Description: PluviómetroPrecision: 0.1 [mm]

kind: Equipment:Sensor meta:

Brand: OTTCalibrate.Date: '2014-05-01'Calibrate.Expires: '2016-08-31'Id.GuMNet: GN00130Install.Date: '2014-08-02'Install.Installer: OTTLocation: G001002

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

58

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Model: Pluvio IIOwner: GUMNETPurchase.Date: '2014-05-01'Purchase.Guarantee.Date: '2016-05-01'Purchase.Price: 3800 [euro]Purchase.Supplier: OTTStatus: Operativo

name: GN00130 OTT Pluvio II parents: - inventory/Station/G001002 - inventory/Variable/G001002.PITR01 - inventory/Variable/G001002.PCTR01 - inventory/Variable/G001002.PCNR01 - inventory/Variable/G001002.PTNR01 - inventory/Variable/G001002.PPTR01 - inventory/Variable/G001002.PPNR01 - inventory/Variable/G001002.TMPP01 table: inventory

La importación se realiza mediante:

python -m gument.inventory bulk-import --yaml equipment.yaml[2.6.1.4_1]

2.6.1.5 Importación de variables y series temporales

Aunque intangibles, las variables medidas en una estación forman parte de suinventario. La definición de una variable incluye un texto descriptivo, lasunidades de medida y la posición de medida respecto del punto de referenciade la estación en coordenadas cilíndricas:

- name: G001002.TMPA01 table: inventory kind: Variable parents: [inventory/Station/G001002] data:

Station: G001002Name: TMPA01Description: Temperatura del aireUnits: '[degC]'PolarCoords: Z: 2 [m]

R: 0.2 [m] A: 35 [deg]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

59

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Las series temporales son medidas concretas de una variable abstracta,tomadas con un intervalo de integración y un tipo estadístico (por ejemplo,medias diezminutales o máximas diarias). La entrada de inventario documentalas particularidades de cada serie temporal:

- name: G001002.TMPA01#10MN.AVG kind: TimeSeries table: inventory parents: [inventory/Variable/G001002.TMPA01] data:

IntegrationTime: 10 [min]Statistic: MeanAccumulation: Mean

Tanto las variables como las series temporales representan informacióndescriptiva para el inventario de la estación. Como tal, se puede ampliar lainformación recogida en el campo data con cualesquiera otras informacionesque se estime oportuno.

Podemos listar las variables mediante:python -m gumnet.inventory list --kind Variable%%

[2.6.1.5_1]

En forma de tabla: python -m gumnet.inventory list --kind Variable%% --table name

[2.6.1.5_2]

Y las asociadas a una estación:python -m gumnet.inventory list --kind Variable --parents inventory/Station/G001002

[2.6.1.5_3]

En forma de tabla:python -m gumnet.inventory list --kind Variable --parents inventory/Station/G001002 --table name

[2.6.1.5_4]

Podemos listar series temporales mediante: python -m gumnet.inventory list --kind TimeSeries

[2.6.1.5_5]

En forma de tabla:python -m gumnet.inventory list --kind TimeSeries --table name

[2.6.1.5_6]

Y las asociadas a una estación:python -m gumnet.inventory list --kind TimeSeries --name G001002%%

[2.6.1.5_7]

En forma de tabla:python -m gumnet.inventory list --kind TimeSeries --name G001002%%--table name

[2.6.1.5_8]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

60

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

[CU-DAT 19]

La definición operativa de una serie temporal a efectos de cálculo se estableceen la tabla de intervalos.

2.6.1.6 Importación en bloque

A la hora de importar estaciones en bloque debemos tener en cuenta el ordende las dependencias. Típicamente un intervalo de serie temporal dependerá dela serie temporal, que a su vez dependerá de la variable, que dependerá de laestación, que dependerá de la red. Así mismo, los sensores dependerán devariables y equipos y éstos de la estación.

Para resolver correctamente las referencias a los elementos «padre», éstosdeben insertarse antes que sus hijos. Los archivos YAML deberán por tantoinsertarse según la ordenación topológica:

● Red● Estación● Variables● Equipos● Sensores● Series temporales● Intervalos de serie temporal

Guardando los archivos YAML de cada estación en una carpeta y cuidando lanomenclatura, el siguiente script Bash insertará todo el inventario en bloque,respetando la ordenación anterior:

#!/bin/bashfunction insert() {

local TABLE=$1local DIR=$2local GLOB=$3for YAML in $(find "$DIR" -maxdepth 1 -name "$GLOB")do

python -m gumnet.$TABLE bulk-import --yaml "$YAML"done

}function insert_station() {

local STATION=$1

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

61

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

insert inventory $STATION '*-station.yaml'insert inventory $STATION '*-variables.yaml'insert inventory $STATION '*-equipos.yaml'insert inventory $STATION '*-sensores.yaml'insert inventory $STATION '*-timeseries.yaml'insert interval $STATION '*-timeseries-interval.yaml'

}insert inventory . '*-network.yaml'for STATION in $(ls -d */)do

insert_station "$STATION"done

[2.6.1.6_1]

Si se prefiere, se puede incluir los sensores en el YAML de equipos, declarandosiempre el sensor después del equipo al que pertenece.

2.6.2 Consultas de inventario

2.6.2.1 Listar estaciones

python -m gumnet.inventory list --kind Station

[2.6.2.1_1]

O, usando la especialización:

python -m gumnet.inventory.station list

[2.6.2.1_2]

Podemos generar un archivo .KML con la ubicación de todas las estacionespara su visualización con Google Earth utilizando un script:

#!/usr/bin/env pythonfrom gumnet.inventory.station import findprint('''<?xml version="1.0" encoding="UTF-8"?>

<kml xmlns="http :// www . opengis . net / kml /2.2"> <Document>''')for station in find(): name = station.name description = station.meta['Name'] longitude = station.meta['GoogleMaps'][0] latitude = station.meta['GoogleMaps'][1] if 'Geographic.Altitude' in station.meta:

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

62

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

altitude = station.meta['Geographic.Altitude'].split()[0] else: altitude = 0 print(''' <Placemark> <name>{name}</name>

<description>{description}</description><Point>

<coordinates>{latitude},{longitude},{altitude}</coordinates></Point>

</Placemark> '''.format( name=name, description=description, longitude=longitude, latitude=latitude, altitude=altitude ))print(''' </Document></kml>''')

[2.6.2.1_3]

2.6.2.2 Listar equipos

Podemos listar todos los equipos:

python -m gumnet.inventory list --kind Equipment%%[2.6.2.2_1]

[CU-INF 1]

El patrón Equipment%% representa todos los valores kind que empiezan porEquipment, en particular Equipment y Equipment:Sensor. También puedeusarse el carácter *:

python -m gumnet.inventory list --kind 'Equipment*'[2.6.2.2_2]

(La expresión se cierra entre comillas para evitar que Bash la expanda anombres de archivos que empiezan por «Equipment»)

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

63

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

Si queremos listar únicamente los sensores:

python -m gumnet.inventory list --kind Equipment:Sensor[2.6.2.2_3]

Se puede filtrar por estación, por ejemplo, se pueden filtrar los equiposasociados a la estación G001002:

python -m gumnet.inventory list --kind Equipment%% --parents inventory/Station/G001002 --table Id.GuMNet,Brand,Model,SerialNumber

+-----------+-----------------+--------------+--------------+| Id.GuMNet | Brand | Model | SerialNumber |+-----------+-----------------+--------------+--------------+| GN00126 | Young | Wind Monitor | None || GN00127 | Rotronic | HC2-S3 | None || GN00128 | Hukseflux | NR01-05 | 2166 || GN00129 | Felix | SL300 | None || GN00130 | OTT | Pluvio II | None || GN00131 | Campbell | CR3000 | None || GN00132 | Campbell | None | None || GN00133 | Campbell | AM16/32B | None || GN00134 | Campbell | NL115 | None || GN00135 | Exiom solution | 55w | None || GN00136 | Exiom solution | 55w | None || GN00137 | Victron | 55/12 60Ah | None || GN00138 | RoHS phocos | CM04-2.1 | None || GN00139 | Campbell | MET21 | None || GN00140 | Campbell | ENC1618 | None || GN00141 | N/D | None | None || GN00142 | N/D | None | None || GN00143 | interMET | None | None || GN00144 | Delta | None | None |+-----------+-----------------+--------------+--------------+19 rows

[2.6.2.2_4]

Se puede obtener un listado de sensor asociado a una variable, por ejemplo, elsensor que mide la variable G001002.TMPA01:

python -m gumnet.inventory list \ --kind Equipment:Sensor \ --parents inventory/Variable/G001002.TMPA01 \ --table Id.GuMNet,Brand,Model,SerialNumber

[2.6.2.2_5]

+-----------+----------+--------+--------------+

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

64

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

| Id.GuMNet | Brand | Model | SerialNumber |+-----------+----------+--------+--------------+| GN00127 | Rotronic | HC2-S3 | None |+-----------+----------+--------+--------------+1 rows

Se puede obtener el listado de precios de los equipos instalados en unaestación, por ejemplo en la G001002:

python -m gumnet.inventory list \> --kind Equipment%% \> --parents inventory/Station/G001002 \> --table Description,Brand,Model,Purchase.Price

[2.6.2.2_6]

Obteniendo:+--------------------------+----------------+--------------+----------------+| Description | Brand | Model | Purchase.Price |+--------------------------+----------------+--------------+----------------+| Anemoveleta | Young | Wind Monitor | 1200 [euro] || Sonda T/HR | Rotronic | HC2-S3 | 450 [euro] || Radiómetro | Hukseflux | NR01-05 | 3900 [euro] || Sensor altura de nieve | Felix | SL300 | 990 [euro] || Pluviómetro | OTT | Pluvio II | 3800 [euro] || Registrador de datos | Campbell | CR3000 | 3100 [euro] || Tarjeta Compact Flash | Campbell | None | 70 [euro] || Multiplexor | Campbell | AM16/32B | 600 [euro] || Adaptador Ethernet TCP/I | Campbell | NL115 | 320 [euro] || Panel fotovoltaico | Exiom solution | 55w | 90 [euro] || Panel fotovoltaico | Exiom solution | 55w | 90 [euro] || Batería de gel | Victron | 55/12 60Ah | 175 [euro] || Regulador de carga | RoHS phocos | CM04-2.1 | 35 [euro] || Protector de radiación | Campbell | MET21 | 150 [euro] || Armario | Campbell | ENC1618 | 390 [euro] || Vallado con puerta | N/D | None | 3000 [euro] || Torre 10 m | N/D | None | 1600 [euro] || Soporte pluvio | interMET | None | 225 [euro] || Antena alta ganancia | Delta | None | 80 [euro] |+--------------------------+----------------+--------------+----------------+19 rows

Se puede obtener el precio total de los equipos inventariados en una estación,por ejemplo, la estación G001002:

python -m gumnet.inventory list \ --kind Equipment%% \ --parents inventory/Station/G001002 \ --table Purchase.Price \ | tail -n +5 | head -n -3 | awk '{sum+=$2} END {print sum}'

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

65

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

[2.6.2.2_7]

20265

[CU-INF 4]

Se puede hacer una valoración de reposición de elementos de una estacióndiferenciando entre propietarios filtrando por campo Owner.Por ejemplo, se puede hacer una valoración de la reposición de los elementosde la estación G001002 pertenecientes a GuMNet:

python -m gumnet.inventory list --kind Equipment%% --parents inventory/Station/G001002 --meta '{"Owner": "GUMNET"}' --table Purchase.Price | tail -n +5 | head -n -3 | awk '{sum+=$2} END {print sum}'

[2.6.2.2_8]

15585

O, para la totalidad de las estaciones (es decir, filtrando por Owner pero no porparents):

python -m gumnet.inventory list --kind Equipment%% --meta '{"Owner": "GUMNET"}' --table Purchase.Price | tail -n +5 | head -n -3 | awk '{sum+=$2} END {print sum}'

[2.6.2.2_9]

186647

Se puede filtrar por fecha de calibración, por ejemplo, se puede hacer unlistado de equipos cuya calibración caduca en el tercer trimestre de 2016:

python -m gumnet.inventory list --kind Equipment:Sensor --table Id.GuMNet,Brand,Model,SerialNumber,Calibrate.Expires --meta '{"Calibrate.Expires": [{"cmp": ">=", "val": "2016-07-01"}, {"cmp": "<", "val": "2016-10-01"}]}'

[2.6.2.2_10]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

66

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

[CU-INF 3]

+-----------+-----------+--------------+--------------+-------------------+| Id.GuMNet | Brand | Model | SerialNumber | Calibrate.Expires |+-----------+-----------+--------------+--------------+-------------------+| GN00064 | Rotronic | HC2-S3 | 61219029 | 2016-08-30 || GN00001 | OTT | Pluvio II | 345377 | 2016-08-30 || GN00074 | Felix | SL300 | 20120201 | 2016-08-30 || GN00041 | Hukseflux | NR01-05 | 2178 | 2016-08-30 || GN00162 | OTT | Pluvio II | None | 2016-08-31 || GN00161 | Felix | SL300 | None | 2016-08-31 || GN00160 | Hukseflux | NR01-05 | None | 2016-08-31 || GN00159 | Rotronic | HC2-S3 | None | 2016-08-31 || GN00050 | Young | Wind Monitor | None | 2016-08-31 || GN00154 | Rotronic | HC2-S3 | None | 2016-08-31 || GN00152 | Young | Wind Monitor | None | 2016-08-31 || GN00151 | OTT | Pluvio II | None | 2016-08-31 || GN00130 | OTT | Pluvio II | None | 2016-08-31 || GN00129 | Felix | SL300 | None | 2016-08-31 || GN00128 | Hukseflux | NR01-05 | 2166 | 2016-08-31 || GN00127 | Rotronic | HC2-S3 | None | 2016-08-31 || GN00126 | Young | Wind Monitor | None | 2016-08-31 || GN00280 | Felix | SL300 | None | 2016-08-30 || GN0117 | Hukseflux | NR01-05 | None | 2016-08-30 || GN0056 | Rotronic | HC2-S3 | F28024R6 | 2016-08-30 |+-----------+-----------+--------------+--------------+-------------------+20 rows

974

El parámetro --meta permite filtrar por los valores del campo meta de losregistros de inventario. El valor tiene formato JSON y puede comparar porigualdad:

--meta '{"Brand": "Young"}'[2.6.2.2_11]

O por una suma (AND lógico) de criterios comparativos (==, !=, >, >=, <, <=)expresados como una array de diccionarios con campos cmp y val:

--meta '{"Calibrate.Expires": [{"cmp": ">=", "val": "2016-07-01"}, {"cmp": "<", "val": "2016-10-01"}]}'

[2.6.2.2_12]

Por comodidad, se puede escribir el criterio en un archivo (lo llamaremoscompara):

{ "Calibrate.Expires": [

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

67

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

{ "cmp": ">=", "val": "2016-07-01"

},{

"cmp": "<", "val": "2016-10-01"

}, ]}

[2.6.2.2_13]

y utilizar el valor especial - para leer el valor meta desde stdin:

cat compara |\ python -m gumnet.inventory list \ --kind Equipment:Sensor \ --table Id.GuMNet,Brand,Model,Calibrate.Expires \ --meta -

[2.6.2.2_14]

Se puede hacer una lista de los archivos insertados con:

python -m gumnet.inventory.samplefile list[2.6.2.2_15]

o, en formato tabla:

python -m gumnet.inventory.samplefile list \ --table FileDate,name

[2.6.2.2_16]

El listado contiene miles de archivos. Podemos pedir bloques, por ejemplo dediez en diez:

python -m gumnet.inventory.samplefile list \ --table FileDate,name --page 0,10

[2.6.2.2_17]

python -m gumnet.inventory.samplefile list \ --table FileDate,name --page 1,10

[2.6.2.2_18]

Podemos pedir sólo los 10 primeros:

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

68

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

python -m gumnet.inventory.samplefile list \ --table FileDate,name --page 10

[2.6.2.2_19]

Y, si ordenamos por el campo meta FileDate en orden descendente podemospedir los 10 más recientes:

python -m gumnet.inventory.samplefile list \ --table FileDate,name --page 10 \ --order-by FileDate:desc

[2.6.2.2_20]

El parámetro --order-by acepta cualquier campo del registro (kind, created,modified, name) o campo de primer nivel dentro del campo meta del registro(como, aquí FileDate).

Para ver los 10 últimos archivos (por orden de fecha de creación del archivooriginal) de una estación en concreto:

python -m gumnet.inventory.samplefile list \ --meta '{"Station": "G001002"}' \ --table FileDate,Station,name --page 10 \ --order-by FileDate:desc

[2.6.2.2_21]

Para ver la fecha del archivo más reciente de cada una de las estaciones:

for STATION in {\G001001,G001002,G001003,G001004,G001005,\G001006,G001007,G001008,G001009,G001010\}; do python -m gumnet.inventory.samplefile list \ --meta "{\"Station\": \"$STATION\"}" \ --table FileDate --page 1 --order-by FileDate:desc \| tail -n +5 | head -n +1 \| awk -v STATION=$STATION '{print STATION " " $2 " " $3}';\done

[2.6.2.2_22]

G001002 2016-05-11 10:25:33G001003 2016-05-11 15:13:25G001004 2016-05-11 15:21:28G001006 2016-05-11 15:15:44G001007 2016-05-11 15:17:02G001008 2016-02-01 13:12:50

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

69

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

2.6.3 Actualización de inventarioPara actualizar el inventario desde línea de comandos utilizamos el mecanismode bulk-update: descargamos el registro, lo editamos y lo volvemos a subir.

Volcamos el registro deseado a un archivo:

python -m gumnet.inventory list \ --meta '{"Id.GuMNet": "GN00141"}' >temp

[2.6.3_1]

por ejemplo:

5ee79890-504a-40d2-8444-efe3b1f843a5: created: '2016-05-12 08:43:18' kind: Equipment meta:

Brand: N/DId.GuMNet: GN00141Install.Date: '2014-08-02'Location: G001002Owner: PNSGPurchase.Date: '2014-05-01'Purchase.Guarantee.Date: '2016-05-01'Purchase.Price: 3000 [euro]Purchase.Supplier: PNSGStatus: Operativo

modified: '2016-05-12 08:43:18' name: GN00141 N/D parents: - b6dd1bdf-fdf3-45cc-819b-0e7df5bec6a4

[2.6.3_2]

editamos el archivo temp:

5ee79890-504a-40d2-8444-efe3b1f843a5: created: '2016-05-12 08:43:18'

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

70

INTERMET_140101_SATEL-_LOTE4G_INF_MANUAL_USUARIO_5.1

kind: Equipment meta:

Brand: N/DId.GuMNet: GN00141Install.Date: '2014-08-02'Location: G001002Owner: PNSGPurchase.Date: '2014-05-01'Purchase.Guarantee.Date: '2016-05-01'Purchase.Price: 3000 [euro]Purchase.Supplier: PNSGStatus: Retirado

modified: '2016-05-12 08:43:18' name: GN00141 N/D parents: - b6dd1bdf-fdf3-45cc-819b-0e7df5bec6a4

[2.6.3_3]

y actualizamos el registro:

python -m gumnet.inventory bulk-update --yaml temp

[2.6.3_4]

interMET Sistemas y Redes S.L.U. C/Cea Bermúdez 14B, 6ºC. 28003 Madridwww.intermet.es

71