Proyecto UWS (4)

publicado en: Programación, SCADA | 0

En la entrada previa sobre UWS terminaba proponiendo unas líneas de evolución del proyecto. Una de ellas era permitir la utilización de nombres simbólicos, en lugar de direccionamiento absoluto. Como se trata de algo casi directo de hacer (basta añadir un diccionario al ensemble, un método de importación y pequeñas modificaciones del servidor web), me he puesto manos a la obra. El uso de simbólicos permite al programador abstraerse de la estructura interna de los controladores, hace el desarrollo más inteligible, y con ello reduce las posibilidades de equivocación. En la nueva versión es posible agregar un símbolo de la siguiente manera, en Python:

Nota: Aprovecho para decir que he renombrado las áreas del controlador Modbus, y he dejado sus nombres en singular (coil, input, holding y register).
Aunque es posible incorporar los nombres simbólicos picando código, es obvio que no resulta eficiente. Lo ideal es trabajar con ellos en una hoja de cálculo, e importarlos al ensemble. Por ejemplo, podemos crear el siguiente archivo csv, en el que la primera línea contiene los encabezados y las siguientes, en orden, el nombre de la variable, controlador, área de memoria y posición. El separador usado es el punto y coma, para evitar ciertos problemas clásicos con el punto decimal en Windows y Excel.

Datos en csv
Datos en csv

Incorporar estos datos es tan sencillo como hacer una llamada al método importtags del ensemble, pasándole la ruta:

Hecho esto, la lectura y escritura de una variable se puede efectuar a través de los métodos get y set de Tag:

En este punto, existe una posibilidad de mejora del proyecto que reclama nuestra atención. En la versión previa de UWS existía el método fast_deploy, que permitía crear automáticamente los grupos de escaneo de la memoria de los controladores. Esta función permitía desentenderse de la tarea de definir una por una las zonas con información relevante. No obstante, si resolvía un problema, generaba otro, y es que, al desconocer qué datos son de interés para el usuario, se opta por mapear toda la memoria. Sin embargo ahora, una vez hemos importado todas las variables que va a usar la aplicación, se hace evidente que conocemos dónde se ubica la información útil. Sólo hay que revisar las direcciones de la tabla que hemos importado, determinar qué zonas de memoria se demandan, y dentro de cada una de ellas, cuál es el primer y último valor. Con esto, es inmediato definir las áreas y grupos de escaneo. Así, el nuevo método mejorado para lanzar las comunicaciones es smart_deploy:

Hasta aquí lo que toca al motor de comunicación con los controladores. Respecto al servidor web, las peticiones GET /?r y /?w se han redefinido para atender a nombres simbólicos. He mantenido el direccionamiento absoluto, pero con llamadas /?dr y /?dw. Es decir, podemos tener cinco respuestas a una URL:

  • http://[host]:[puerto]/?r:[símbolo] devuelve el valor de la variable con dicho símbolo.
  • http://[host]:[puerto]/?w:[símbolo][valor] escribe el valor de la variable con dicho símbolo.
  • http://[host]:[puerto]/?dr:[plc][memoria][elemento] devuelve el valor de dicho elemento en la memoria de su controlador.
  • http://[host]:[puerto]/?dw:[plc][memoria][elemento] escribe el valor de dicho elemento en la memoria de su controlador.
  • http://[host]:[puerto]/[fichero] entrega un fichero.

Al renombrar la sintaxis de las peticiones para asociar ?r y ?w a los nombres simbólicos, no es necesario actualizar j.js, que ahora trabaja directamente con símbolos en lugar de direccionamientos absolutos.
Otra tarea pendiente era mejorar la parte gráfica. En realidad esto no es una evolución de UWS propiamente hablando, ya que queda en el lado del desarrollo web. Sin embargo, he querido introducir algunas modificaciones para mostrar el potencial de un SCADA de este tipo. No me voy a entretener en describir cómo funciona el nuevo j.js (que será bastante evidente para quien se maneje con Javascript), pero sí debo comentar qué hace con los atributos que localiza en la página:

  • data-dir: Es el atributo que define un elemento como dinámico, y contiene el nombre simbólico que se va a representar. Por defecto, j.js decide qué hacer según la etiqueta que lo contenga:
    • Los campos de texto se interpretan como un espacio para introducir un valor numérico. Se usarán por tanto en la práctica para consignas.
    • Los checkbox permiten modificar valores digitales (un marcha/paro, automático/manual, etc.).
    • Si el atributo pertenece a una etiqueta p o spam, se entiende que su contenido es un valor que se debe visualizar (puede ser numérico o booleano).
    • Por último, si se aplica a una capa o div, el refresco se hace sobre su visibilidad.
  • data-css: Si está presente, las modificaciones no se hacen conforme a lo anterior, sino sobre el elemento de estilo contenido en este atributo. Podemos por tanto, a través de este atributo, alterar el tamaño de un elemento, su visibilidad de nuevo, color, etc.
  • data-transform: Permite realizar transformaciones sobre el valor. Se pueden anidar varias, separadas por punto y coma:
    • invert invierte el valor de una señal digital.
    • scale:[x0],[x1],[y0],[y1] lleva a cabo un escalado, conforme a la recta (x0,y0)-(x1,y1).

    Mediante estas nuevas funcionalidades, se puede hacer un SCADA perfectamente funcional como el que se muestra en la siguiente imagen:

    SCADA gráfico UWS
    SCADA gráfico UWS

    Para quien desee hacer pruebas, dejo enlace al código, como otras veces.
    Esta entrada continúa en Proyecto UWS (5).
    Recursos asociados:
    SCADA UWS (versión 1.1) y código de ejemplo.

Proyecto UWS (3)

publicado en: Programación, SCADA | 0

En la entrada previa mostré cómo se configuraba una red de controladores en UWS, y concluía con el arranque del servidor web. Quedó pendiente cómo desarrollar la interfaz del SCADA. Aunque al acometer la parte gráfica no es necesario comprender bien cómo funciona el propio servidor, resulta conveniente para conocer sus posibilidades. Cuando lo instanciamos se le pasan tres parámetros: una tupla con la interfaz y puerto de escucha, el manejador y el ensemble:

Hecho esto, una hebra se encargará de atender las peticiones HTTP que lleguen por dicho puerto con el método GET. En román paladino, cuando escribamos la dirección del servidor en un navegador recibiremos una respuesta, en función de la URL que se esté demandando. El formato de una petición sería como sigue:

Respecto a la dirección del servidor no creo que haya lugar a dudas. Si hemos arrancado el UWServer con la línea antedicha y queremos acceder al SCADA desde el propio equipo, escribiríamos en el navegador http://127.0.0.1:80 (o http://localhost:80, o simplemente http://localhost). La parte interesante está en la cadena recurso. Tenemos tres alternativas:

  • Lectura de un valor. Para conocer un valor de un controlador, el recurso debe adoptar la forma ?r:[plc]:[memoria]:[elemento]. Por ejemplo, si en la situación descrita en la entrada previa queremos conocer la entrada analógica 2 (la tercera, ya que empezamos a contar por 0), la URL que debemos escribir sería http://localhost:8080/?r:plc1:registers:2. El navegador nos devuelve directamente su valor en HTTP. Sencillo, ¿no?
  • Escritura de un valor. De la misma forma, podríamos modificar un valor en uno de los controladores. La cadena de recurso en este caso sería ?w:[plc]:[memoria]:[elemento]:[valor]. En la misma situación anterior, si quisiésemos escribir un 50 en el primer registro de retención (dirección 0), lo haríamos pidiendo desde el navegador http://localhost:8080/?w:plc1:holdings:0:50. Podemos ver cómo en el controlador, dicho registro se pone en 50.
  • En cualquier otro caso, se nos devolverá, como un servidor web al uso, el fichero localizado en la ruta relativa, que por defecto es www. Por ejemplo, podemos crear una página de bienvenida index.html, situarla dentro de www, y verla con http://localhost:8080/index.html (o de forma más simple, http://localhost:8080).

No necesitamos nada más para elaborar la interfaz. Con esto es suficiente para crear una página web, y un poco de Javascript nos debería permitir el refresco de la representación y el envío de las escrituras. Se puede objetar que el código que habría que elaborar es engorroso, pero aquí es donde entra en juego la magia de jQuery Ajax. En el ejemplo que hemos dado, he incluido el fichero j.js, que permite olvidarse de toda esta tarea (en realidad, de todo lo que he explicado hasta el momento). Su uso es simple, y sólo hay que hacer dos cosas:

  • En la página que desarrollemos hay que incluir una referencia a jQuery y a j.js:
  • A cada elemento dinámico hay que agregarle el atributo data-dir, cuyo valor será la dirección del dato que se desea representar. La sintaxis es la misma antes descrita ([plc]:[memoria]:[elemento]). Es decir, para mostrar el estado de la bobina número 1, el código HTML sería el siguiente:
    Si además nos interesa poder modificarlo, la etiqueta adecuada es sin duda un input:

Con estos atributos data-dir, podemos desentendernos de la programación asociada a la página. El código en j.js hace lo necesario. Por un lado asocia a las etiquetas susceptibles de ser modificadas (input de tipo checkbox y text) los eventos correspondientes, de modo que ante un cambio envíen la escritura al servidor. Por otro, se lanza un temporizador para refrescar periódicamente los valores, tanto de las etiquetas anteriores como de los div, que no se pueden modificar. El tiempo de refresco, que es de 1000ms por defecto, se puede determinar mediante el siguiente elemento oculto HTML:

Por supuesto, todo lo descrito hasta aquí es muy mejorable. Así a bote pronto se me ocurren las siguientes líneas de desarrollo para las próximas versiones de UWS:

  • Utilizar los websockets de HTML5 para el refresco de la página, en vez de solicitar periódicamente los datos, mediante un modelo de suscripción. Con esto se gana agilidad y se disminuye el tráfico de red.
  • Añadir nuevas funcionalidades a j.js, como alterar la visibilidad de elementos, dimensiones, etc. Mediante atributos adicionales, también se puede agregar transformaciones sobre valores, como inversión o escalado.
  • Introducir en el ensemble un diccionario, para referenciar los datos mediante nombres simbólicos. Lo ideal sería cargar dichos nombres desde fichero o base de datos, en lugar de picarlos en Python.
  • Agregar nuevos protocolos de comunicación con controladores. También otras formas de conectividad con el ensemble.
  • Por último, un SCADA no puede estar completo sin alarmas e históricos.

Esta entrada continúa en Proyecto UWS (4).
Recursos asociados:
SCADA UWS (versión 1.0) y código de ejemplo.

Proyecto UWS (2)

publicado en: Modbus, Programación, SCADA | 0

He terminado la fastidiosa tarea de documentar el Proyecto UWS. Y de camino me ha servido para corregir un par de errores. Como comentaba, el UWS es un esbozo de SCADA muy en pañales. Corre en Python (yo uso concretamente la versión 3.5) y la interfaz es HTML estándar. De momento sólo comunica por Modbus TCP, pero todo se andará.
Los módulos y clases de los que se compone son los siguientes:

  • PLCModule:
    • PLC: Representación de un controlador genérico.
    • Memory: Representación de una de las zonas de memoria de un PLC. En el caso de un equipo Modbus, van a ser bobinas, entradas digitales, registros de retención y registros de entradas. Pero otros controladores exigirán otra distribución.
    • Area: Segmento de memoria. Su uso es interno, normalmente no va a requerir que el programador la ataque.
    • Poll: Conjunto de áreas (información) que se piden con una misma frecuencia de muestreo. Por ejemplo, valores que cambian muy rápido o son críticos requieren refresco con intervalo reducido.
  • MBPLCModule:
    • MBPLC: Controlador con comunicación Modbus. Deriva de la clase PLC.
  • EnsembleModule:
    • Ensemble: Vendría a ser una red de controladores. Pero en realidad no hay exigencia real de que se encuentren en la misma red. En el fondo es un conjunto de controladores y de grupos de muestreo.
  • UWServerModule:
    • UWServer: El SCADA propiamente dicho. En principio sólo integra los componentes.
    • WebServer: El servidor web.

Me va a perdonar el lector por el revuelto de idiomas: clases, atributos, métodos, etc. están nombrados usando el inglés, pero tengo poca soltura y mucha pereza para usar la misma lengua para los docstrings, de modo que los he redactado en español.
El siguiente gráfico muestra los componentes de un proyecto:

Componentes de UWServer
Componentes de UWServer

En la otra entrada puse un ejemplo de cómo se llevaría a cabo un proyecto, sin apenas dar explicaciones. Me gustaría repasarlo de nuevo, explicando más en detalle los pasos. Básicamente el desarrollo se realiza en dos espacios. En Python se define la estructura del proyecto (controladores, conexiones, muestreos…) y en HTML se compone la interfaz del SCADA. Comencemos por la primera, que nos va a llevar el resto de la entrada. Por lo usual, en primer lugar debemos instanciar un Ensemble, es decir, una red de controladores.

En nuestro ejemplo sólo vamos a requerir que el ensemble tenga un controlador, al que vamos a llamar plc1. Como comunicamos con él en Modbus TCP, hay que indicarle su dirección IP. También cuánto ocupan sus distintas áreas de memoria (coils, inputs, holdings y registers). La clase nos permite aportar más parámetros, como puerto de conexión (típicamente 502), método, unidad (número de esclavo), reintentos caso de fallo de comunicación. También atributos para saber si se ha establecido la comunicación, métodos para leer o escribir datos, e incluso podríamos definir áreas adicionales de memoria con un sentido algo peregrino. Pero para nuestro ejemplo no nos vamos a complicar: la longitud de todas sus áreas de memoria va a ser de 20 elementos y el resto de parámetros quedan por defecto. También aprovechamos para agregarlo al ensemble en el mismo paso:

Ahora vendría la tarea fastidiosa de definir diferentes muestreos, según periodo de refresco, y las áreas que se leen. Un ejemplo de cómo se crearía uno de estos grupos es el siguiente:

Hago notar que propiamente hablando, el tiempo de muestreo es “entre muestreos”. Es decir, el código espera a que se hayan completado las comunicaciones (o hayan devuelto error) antes de empezar a contar para las siguientes peticiones. Estamos hablando comunicación desde un SCADA, no en un bus de campo, con lo que podemos ser algo laxos en este sentido. Se evita así además saturar las comunicaciones por solapamientos. Para continuar con el ejemplo, ahora habría que iniciar las comunicaciones con cada uno de los grupos de muestreos definidos.

Aunque de esta forma se controla de forma fina cómo se van a llevar a cabo las comunicaciones, he querido incorporar un método más ágil. fast_deploy crea un único grupo de muestreo con el tiempo por defecto, añade todas las áreas de memoria al completo de todos los PLC que posea el ensemble, e inicia sus comunicaciones de una tacada:

En este momento tenemos el motor de comunicación en marcha, y podemos leer y escribir de la forma siguiente:

En estas circunstancias, tan solo nos falta lanzar el servidor web. Lo normal sería usar el puerto 80, pero se puede usar cualquier otro disponible, como el 8080. Por supuesto, tenemos libertad para emplear más de un puerto con diferentes servidores, y el mismo ensemble. Puede ser interesante conjugado con otro de los parámetros, la ruta relativa de los ficheros HTML, que por defecto es www.

Queda discutir la segunda parte, donde entraremos en el desarrollo de la interfaz web. Eso será en una próxima entrega.
Esta entrada continúa en Proyecto UWS (3).
Recursos asociados:
SCADA UWS (versión 1.0) y código de ejemplo.

Novedades 20160118

Los fabricantes de controladores cada vez se toman más en serio la conectividad de sus equipos, y no me refiero a nivel de campo. Las instalaciones de control aisladas renuncian al enorme potencial de la integración con el resto de la organización. Si hace poco hablaba de la librería TCP File Server de Siemens, Omron ha dado un paso más allá. Los NJ501 y NJ101 comunican directamente con bases de datos, sin intermediarios. Ellos lo enfocan a control numérico, se puede pensar en el IoT… pero la clave está en la gestión unificada de la producción.
La Agencia Europea de Seguridad de las Redes y de la Información (ENISA) ha publicado un estudio sobre el grado de madurez de la seguridad en los sistemas SCADA e ICS, orientado a las actividades de los estados miembros, sus legislaciones y estrategias. España destaca en la formación, debido a los cursos del INCIBE y la Universidad de León. El estudio también propone una serie de recomendaciones: alinear esfuerzos, buenas prácticas, estandarización, alertas, sensibilización, formación e investigación.
Omron dispone de una plataforma de formación online gratuita en la que se pueden encontrar cursos de diversas materias: sistemas de automatización, control, motores, fuentes, relés, interruptores, componentes de seguridad, sensores, visión, ahorro energético… Los textos son muy claros, en español, y no requieren un nivel elevado, de modo que constituyen un material muy interesante para quien quiera iniciarse por su cuenta.
Keith Blodorn, de ProSoft Technology, ha descrito recientemente en un artículo las características fundamentales de la Industria 4.0. Se centra en remarcar la evolución frente a la integración de sistemas tradicional, que en realidad es bastante gradual: lo que supone en cuanto a supervisión remota, movilidad e interoperatividad. Y precisamente debido a que es una evolución, más que revolución, la adaptación es sencilla, teniendo presente aspectos como escalabilidad, migración de red y ciberseguridad.
Telefónica ha publicado su libro blanco sobre las smart cities, una buena visión del estado del arte. A mi modo de ver, lo más interesante está en la cuarta parte. Tras esbozar una hoja de ruta, se ahonda en las relaciones que se deben establecer entre actores (ciudadanos, universidad, empresas, administración), el marco legal, la financiación y los modelos. De manera demasiado breve también se presenta algún caso práctico, como el de Rivas Vaciamadrid. Por último, el libro propone un decálogo para las las futuras ciudades inteligentes.

Proyecto UWS (1)

publicado en: Diseño web, Raspberry Pi, SCADA | 0

Este año los reyes me llegaron con unos días de retraso, pero han valido la pena. Traían una flamante Raspberry Pi 2 B, con la que me he puesto a trastear un poco. Tenía ganas de programar un mini SCADA, que pudiese correr en un pequeño controlador como éste y que fuese accesible desde un navegador web. Sobra decir que es una primerísima versión todavía en pañales, posiblemente plagada de fallos y con una documentación escasa, por no decir ausente. Por tanto, no aconsejo de momento su uso para aplicaciones sensibles. Poco a poco iré mejorándola en los ratos libres.

Raspberry Pi 2 B
Raspberry Pi 2 B

Me gustaría en primer lugar dar una idea rápida del objetivo, así que voy a arrancar con una exposición en caliente. El único requisito de partida es un controlador con puerto Ethernet que pueda correr Python. He usado la Raspberry pero bien podría servir un PC con Windows, o Linux, o incluso algunas tablets. El SCADA, al que he dado en llamar Universal Web Server, tiene de momento poco de universal, ya que sólo comunica en Modbus TCP. Por tanto, también hará falta un servidor que comunique en este protocolo. Lo hacen muchos autómatas; yo cuento con un simulador. En estas circunstancias, nuestro SCADA consiste en un breve código en Python que da de alta dicho esclavo, inicia las comunicaciones con él y va sirviendo la información vía web. Quedaría como sigue:

Al ejecutar este código se hace todo lo que hemos comentado. He preparado una página donde se pueden ver los primeros valores de las áreas de memoria del PLC (coils, discrete inputs, holdings y register inputs). Como es de esperar, también es posible modificar datos cuando están accesibles para escritura.
Por supuesto, como SCADA es algo esquemático. El motivo es mi pereza, no la funcionalidad de UWS. Por terminar de mostrar el código del ejemplo, que pasaré a comentar en sucesivas entradas, copio a continuación el HTML de la página. Espero que, como creo haber hecho con la parte de Python, la sintaxis sea lo bastante simple como para, incluso sin describir los detalles, el contenido sea intuitivo. Se hace notar que no es necesario ejecutar código adicional, ya que el script en j.js se encarga de localizar todas aquellas etiquetas con atributo data-dir, interpretarlas como elementos dinámicos, y asociarles los eventos necesarios, que varían en función del tipo de etiqueta. Por tanto, podemos incluir tantas páginas como queramos con un desarrollo web al uso. Basta incluir los archivos, como index.html, dentro de la carpeta www, que debe estar situada en la ruta desde la que estamos ejecutando la aplicación.

Por último, hacer notar que las comunicaciones Modbus de este ejemplo hacen uso del paquete pymodbus3. Se puede instalar a través de pip con:

A continuación incluyo el enlace a la aplicación en Python, los módulos de que depende y la página web de este ejemplo. En las siguientes entradas iré documentando la API y espero que ampliando la funcionalidad y protocolos de comunicación. Espero que os sea de utilidad.
Esta entrada continúa en Proyecto UWS (2).
Recursos asociados:
SCADA UWS (versión 1.0) y código de ejemplo.