Expresiones
El único lenguaje de expresiones que hay detrás de las variables y de las condiciones de alarma, qué puede referenciar, la superficie de lectura de cada clase de punto, las reglas que impone el evaluador, los mensajes que da la validación, y cómo funcionan el editor de scripts y su selector Examinar…
Un mismo lenguaje de expresiones sirve a dos sitios de la página Logic: lo que calcula una variable de expresión y la condición que vigila una alarma. Las dos son una sola expresión JavaScript evaluada en modo estricto dentro de un aislamiento sin acceso a la máquina, y las dos se editan en el mismo editor de scripts. Los scripts de acción usan el mismo vocabulario, pero son bloques de sentencias; sus diferencias están en Acciones.
Qué es una expresión
Una expresión es exactamente una expresión JavaScript: literales, aritmética, comparaciones, operadores lógicos, el condicional a ? b : c, operaciones de texto, cadenas de plantilla, y llamadas a los objetos integrados de JavaScript Math, Date y JSON. Las sentencias (let, if, bucles) pertenecen a las acciones: una segunda sentencia se rechaza con "Una variable contiene una sola expresión. Las sentencias pertenecen a las acciones." Las asignaciones y los ++/-- en cualquier punto de una expresión se rechazan con "Las expresiones son de solo lectura. Las escrituras pertenecen a las acciones."
La expresión referencia los puntos por su dirección enraizada. Lo que entrega cada raíz a la expresión:
| Raíz | Qué cruza hacia la expresión |
|---|---|
Los tags de Connector, Variables, Alarms, los Channels de una unidad de Process |
Un objeto en vivo con la superficie de lectura tipada de abajo. Una referencia pelada (Connector.Simulated.Pump.Flow a solas) se evalúa como el valor del punto; una alarma pelada, como su IsActive. |
System, Server, Assets, y el estado del ensayo, la producción, los comandos y la preparación de una unidad de Process |
El valor actual en sí: un número, un texto, un booleano o un instante. Úselo directamente; no hay ningún miembro que añadir. |
System.Now es el instante de la evaluación: todas las referencias a él dentro de una misma evaluación leen la misma hora. Cruza como un Date de JavaScript, igual que toda marca de tiempo, así que los instantes se comparan y se restan con naturalidad: (System.Now - Connector.Simulated.Pump.Run.SourceTimeStamp()) / 1000 son segundos.
Una variable de expresión puede referenciar tags, variables de memoria, alarmas, puntos de Process, puntos de Assets y los diagnósticos de System y de Server, pero nunca otra variable de expresión: el editor lo rechaza ("'Variables.X' es una variable de expresión. Las expresiones no pueden hacer referencia a otras variables de expresión; haga referencia a variables de memoria o a los puntos subyacentes.") para que los resultados nunca dependan del orden de evaluación. Una condición de alarma puede referenciarlo todo menos Alarms.* ("Las condiciones de alarma no pueden hacer referencia a otras alarmas.") y tiene que producir un booleano.
La superficie de lectura de un punto
Un tag en vivo ofrece:
| Miembro | Devuelve | Significado |
|---|---|---|
.Value |
valor tipado | El valor de ingeniería, después de toda la cadena de conversión del tag |
.ValueRaw |
valor tipado | El valor bruto normalizado al tipo declarado del tag, antes del escalado |
.ValueObject |
cualquier cosa | El valor exactamente como lo produjo el controlador |
.ValueScaled, .ValueCalibrated, .ValueLimited, .ValueRounded |
número | El valor después de las etapas Escala, Calibración, Límites y Decimales |
.ValueToBool(), .ValueToInteger(), .ValueToReal(), .ValueToString(), .ValueToDateTime() |
valor convertido | El valor de ingeniería convertido a esa categoría; sin valor sigue siendo sin valor |
.State() |
booleano | Calidad: verdadero mientras la lectura es buena |
.SourceTimeStamp() |
Date | Cuándo produjo el dispositivo la lectura |
.ApplicationTimeStamp() |
Date | Cuándo la recibió el servidor integrado |
.Name, .EngineeringUnit |
texto | El nombre y la unidad del tag |
Una variable ofrece .Value, las cinco conversiones .ValueTo*(), .State(), .ApplicationTimeStamp(), .Name y .EngineeringUnit. Una alarma ofrece .IsActive, .IsAcked, .CurrentState, .State() (si su condición se pudo evaluar en el último ciclo), .ActiveSince(), .LastTransitionAt() y .Name. Un canal de Process ofrece la superficie de tag cuando está vinculado a un tag, y la superficie de variable cuando lo está a una variable; un canal sin vínculo no ofrece nada. En un objeto en vivo no se alcanza nada más: un miembro fuera de esta superficie se lee como indefinido, y llamarlo falla en la validación. El selector Examinar… lista esos mismos miembros bajo cada punto, así que ninguno hay que escribirlo de memoria.
Las reglas que impone el evaluador
Tanto en el editor mientras se escribe como de nuevo en cada ciclo de 100 ms:
- La puerta de la calidad. Antes de evaluar, todos los puntos referenciados se resuelven y se refrescan. Cualquier punto que falte, que sea malo o que no contenga valor convierte el resultado en un hueco de mala calidad sin llegar a ejecutar la expresión, así que un tag sin conexión nunca puede fabricar una muestra y un
nullnunca llega al motor para convertirse en un0. - Los resultados no finitos son huecos. Un NaN o un infinito (una división por cero, una aritmética indefinida) nunca se convierte en una muestra.
- Protección contra desbocamiento. Una evaluación se aborta al pasar de 250 ms, de 5.000 sentencias o de 4 MB de memoria de script, y cuenta como un hueco de mala calidad. Se mantiene un motor por texto de expresión, así que de otra expresión no se filtra nada.
- Conversión. Un resultado correcto se convierte al tipo de salida de la variable; una condición de alarma se convierte a booleano, y un resultado que no se puede convertir mantiene el estado de la alarma.
- Los errores son huecos, no excepciones. Un error de ejecución en el momento del ciclo produce un hueco y una entrada en el diario técnico (el primer fallo, resúmenes mientras se repite, y una línea cuando se recupera); el ciclo sigue con la variable siguiente.
Lo que la validación rechaza
El editor valida el borrador cada medio segundo y muestra el primer problema bajo el valor o bajo la condición:
| Mensaje | Causa |
|---|---|
| Se necesita una expresión. / Se necesita una condición. | El editor está vacío. |
| Error de expresión: … | El texto no se puede analizar. |
| Una variable contiene una sola expresión. Las sentencias pertenecen a las acciones. | Más de una sentencia, o una sentencia que no es una expresión. |
| Las expresiones son de solo lectura. Las escrituras pertenecen a las acciones. | Una asignación o un ++/--. |
| Las direcciones deben ser estáticas: se accede a 'Root' con un segmento calculado. | Variables[name] o cualquier segmento que no sea literal. |
| Dirección incompleta 'Connector.Simulated'. | Una cadena demasiado corta para nombrar un punto bajo su raíz. |
| No se encontró 'X'. | La dirección no resuelve nada. |
| 'X' es una variable de expresión. … | Una referencia a otra variable de expresión. |
| Las condiciones de alarma no pueden hacer referencia a otras alarmas. | Una referencia Alarms.* en una condición. |
| La condición debe evaluarse como Bool, pero produjo 'x'. | La evaluación de prueba de una condición produjo un valor presente que no se convierte a booleano. |
| Error de expresión: aquí no se puede usar un punto en vivo directamente. Léalo por su miembro .Value (por ejemplo, Connector.Driver.Device.Tag.Value). | Un objeto en vivo usado donde hace falta un primitivo (Tag + 1). |
Error de expresión: <engine message> |
La evaluación de prueba lanzó un error: un identificador desconocido, un miembro bloqueado llamado como función. |
La evaluación de prueba corre con los valores actuales al margen de la calidad, así que un mensaje refleja la expresión y no una entrada mala; una entrada mala se muestra en la tarjeta PUNTOS REFERENCIADOS.
El editor de scripts
Todas las expresiones, las condiciones y los scripts de la página se editan en la misma tarjeta: un rótulo superior (EXPRESIÓN, CONDICIÓN o SCRIPT), un botón Examinar…, el editor, una indicación y el mensaje de validación. El editor es CodeMirror con resaltado de JavaScript, un histórico de deshacer y autocompletado de fichas de dirección: los nombres de raíz para una ficha pelada, luego los hijos de la ruta escrita hasta ese momento, con los miembros incluidos en cuanto la ficha nombra un punto (introducir una dirección). El texto se empuja al borrador con retardo y se guarda solo. Las cajas de expresión y de condición miden 56 px de alto como mínimo, y la del script de una acción 160 px. Cuando el motor del editor no puede arrancar, la caja degrada a un área de texto sencilla que sigue leyendo y escribiendo, sin resaltado, sin autocompletado y sin histórico; Examinar… añade entonces la dirección elegida al final en lugar de en el cursor.
Examinar… abre un diálogo ("Examinar: insertar en EXPRESIÓN") con el árbol a nivel de miembro de todo el espacio de direcciones; seleccione una fila y pulse Insertar, o haga doble clic en ella, para poner su dirección en el cursor. Cada editor es dueño de su propio diálogo, así que dos editores de una misma página nunca comparten una selección.
Lo que las expresiones no hacen
No escriben nada, no llaman a los comandos de ensayo de Process, no guardan estado entre evaluaciones, no pueden definir funciones compartidas entre expresiones, y no se evalúan bajo demanda: el ciclo las publica cada 100 ms y el editor previsualiza el borrador dos veces por segundo.