Expressões
A única linguagem de expressão atrás das variáveis e das condições de alarme, o que ela pode referenciar, a superfície de leitura de cada tipo de ponto, as regras que o avaliador impõe, as mensagens que a validação dá, e como o editor de script e o seletor Procurar… funcionam.
Uma única linguagem de expressão serve a dois lugares da página Logic: o que uma variável de expressão calcula e a condição que um alarme vigia. As duas são uma expressão JavaScript avaliada em modo estrito dentro de uma caixa isolada, sem acesso à máquina, e as duas são editadas no mesmo editor de script. Scripts de ação usam o mesmo vocabulário, mas são blocos de instruções; as diferenças deles estão em Ações.
O que é uma expressão
Uma expressão é exatamente uma expressão JavaScript: literais, aritmética, comparações, operadores lógicos, o condicional a ? b : c, operações de texto, cadeias de modelo e chamadas aos embutidos do JavaScript Math, Date e JSON. Instruções (let, if, laços) pertencem às ações: uma segunda instrução é recusada com "Uma variável guarda uma única expressão. Instruções pertencem às Ações." Atribuições e ++/-- em qualquer lugar de uma expressão são recusados com "As expressões são somente leitura. As escritas pertencem às Ações."
A expressão referencia pontos pelo endereço enraizado deles. O que cada raiz entrega à expressão:
| Raiz | O que atravessa até a expressão |
|---|---|
Tags de Connector, Variables, Alarms, os Channels de uma unidade do Process |
Um objeto ao vivo com a superfície de leitura tipada abaixo. Uma referência nua (Connector.Simulated.Pump.Flow sozinha) avalia para o valor do ponto; um alarme nu, para o IsActive dele. |
System, Server, Assets, e o estado da execução, a produtividade, os comandos e a preparação de uma unidade do Process |
O valor atual em si: um número, um texto, um booleano ou um instante. Use-o diretamente; não há membro a acrescentar. |
System.Now é o instante da avaliação: toda referência a ele dentro de uma avaliação lê a mesma hora. Ele atravessa como um Date do JavaScript, como todo carimbo de tempo, então instantes comparam e subtraem naturalmente: (System.Now - Connector.Simulated.Pump.Run.SourceTimeStamp()) / 1000 são segundos.
Uma variável de expressão pode referenciar tags, variáveis de memória, alarmes, pontos do Process, pontos de Assets e os diagnósticos de System e Server, mas nunca outra variável de expressão: o editor a recusa ("'Variables.X' é uma variável de expressão. Expressões não podem referenciar outras variáveis de expressão; referencie variáveis de memória ou os pontos de base.") para que os resultados nunca dependam da ordem de avaliação. Uma condição de alarme pode referenciar tudo, menos Alarms.* ("Condições de alarme não podem referenciar outros alarmes.") e precisa produzir um booleano.
A superfície de leitura de um ponto
Uma tag ao vivo oferece:
| Membro | Devolve | Significado |
|---|---|---|
.Value |
valor tipado | O valor de engenharia, depois da cadeia de conversão inteira da tag |
.ValueRaw |
valor tipado | O valor bruto normalizado para o tipo declarado da tag, antes da escala |
.ValueObject |
qualquer coisa | O valor exatamente como o driver o produziu |
.ValueScaled, .ValueCalibrated, .ValueLimited, .ValueRounded |
número | O valor depois dos estágios de Escala, Calibração, Limites e Decimais |
.ValueToBool(), .ValueToInteger(), .ValueToReal(), .ValueToString(), .ValueToDateTime() |
valor convertido | O valor de engenharia convertido para aquela categoria; nenhum valor continua nenhum valor |
.State() |
booleano | Qualidade: verdadeiro enquanto a leitura é boa |
.SourceTimeStamp() |
Date | Quando o dispositivo produziu a leitura |
.ApplicationTimeStamp() |
Date | Quando o servidor embutido a recebeu |
.Name, .EngineeringUnit |
texto | O nome e a unidade da tag |
Uma variável oferece .Value, as cinco conversões .ValueTo*(), .State(), .ApplicationTimeStamp(), .Name e .EngineeringUnit. Um alarme oferece .IsActive, .IsAcked, .CurrentState, .State() (se a condição dele pôde ser avaliada na última varredura), .ActiveSince(), .LastTransitionAt() e .Name. Um canal do Process oferece a superfície de tag quando está vinculado a uma tag, e a superfície de variável quando está vinculado a uma variável; um canal sem vínculo não oferece nada. Nada mais num objeto ao vivo é alcançável: um membro fora desta superfície lê como indefinido, e chamar um falha na validação. O seletor Procurar… lista esses mesmos membros sob cada ponto, então nenhum deles precisa ser digitado de memória.
As regras que o avaliador impõe
Tanto no editor, enquanto você digita, quanto de novo a cada varredura de 100 ms:
- A porteira da qualidade. Antes de avaliar, todo ponto referenciado é resolvido e atualizado. Qualquer ponto ausente, Ruim ou sem valor faz o resultado ser uma lacuna de qualidade ruim sem rodar a expressão, então uma tag offline nunca consegue fabricar uma amostra e
nullnunca chega ao motor para virar0. - Resultados não finitos são lacunas. NaN ou infinito (divisão por zero, aritmética indefinida) nunca vira uma amostra.
- Proteção contra descontrole. Uma avaliação é abortada além de 250 ms, 5.000 instruções ou 4 MB de memória de script, e conta como lacuna de qualidade ruim. Um motor é mantido por texto de expressão, então nada vaza de outra expressão.
- Conversão. Um resultado bem-sucedido é convertido para o tipo de saída da variável; uma condição de alarme é convertida para booleano, e um resultado que não converte mantém o estado do alarme.
- Erros são lacunas, não exceções. Um erro de execução no momento da varredura produz uma lacuna e uma entrada de diário (a primeira falha, resumos enquanto ela se repete, uma linha quando ela se recupera); a varredura segue com a próxima variável.
O que a validação recusa
O editor valida o rascunho a cada meio segundo e mostra o primeiro problema abaixo do valor ou da condição:
| Mensagem | Causa |
|---|---|
| Uma expressão é obrigatória. / Uma condição é obrigatória. | O editor está vazio. |
| Erro de expressão: … | O texto não é interpretável. |
| Uma variável guarda uma única expressão. Instruções pertencem às Ações. | Mais de uma instrução, ou uma instrução que não é uma expressão. |
| As expressões são somente leitura. As escritas pertencem às Ações. | Uma atribuição ou ++/--. |
| Os endereços precisam ser estáticos: 'Root' é acessada com um segmento calculado. | Variables[name] ou qualquer segmento que não seja literal. |
| Endereço incompleto 'Connector.Simulated'. | Uma cadeia curta demais para nomear um ponto sob a raiz dela. |
| 'X' não foi encontrado. | O endereço não resolve para nada. |
| 'X' é uma variável de expressão. … | Uma referência a outra variável de expressão. |
| Condições de alarme não podem referenciar outros alarmes. | Uma referência a Alarms.* numa condição. |
| A condição precisa avaliar para um booleano, mas produziu 'x'. | A avaliação de teste de uma condição produziu um valor presente que não converte para booleano. |
| Erro de expressão: um ponto ao vivo não pode ser usado diretamente aqui. Leia-o pelo membro .Value dele (por exemplo Connector.Driver.Device.Tag.Value). | Um objeto ao vivo usado onde um primitivo é necessário (Tag + 1). |
Erro de expressão: <mensagem do motor> |
A avaliação de teste lançou um erro: um identificador desconhecido, um membro bloqueado chamado como função. |
A avaliação de teste roda com os valores atuais, seja qual for a qualidade, então uma mensagem reflete a expressão, e não uma entrada Ruim; uma entrada Ruim aparece no cartão PONTOS REFERENCIADOS.
O editor de script
Toda expressão, condição e script da página é editado no mesmo cartão: um rótulo de grupo (EXPRESSÃO, CONDIÇÃO ou SCRIPT), um botão Procurar…, o editor, uma dica e a mensagem de validação. O editor é o CodeMirror com realce de JavaScript, um histórico de desfazer e autocompletar de símbolos de endereço: nomes de raiz num símbolo isolado, depois os filhos do caminho digitado até ali, com os membros incluídos assim que o símbolo nomeia um ponto (digitar um endereço). O texto é empurrado para o rascunho com atraso e salvo sozinho. As caixas de expressão e de condição têm no mínimo 56 px de altura, e a caixa de script de ação tem 160 px. Quando o motor do editor não consegue iniciar, a caixa se degrada para uma área de texto simples, que ainda lê e escreve, sem realce, sem completar e sem histórico; o Procurar… então acrescenta o endereço escolhido no fim, em vez de no cursor.
O Procurar… abre um diálogo ("Procurar: inserir em EXPRESSÃO") com a árvore do espaço de endereços inteiro, até o nível de membro; selecione uma linha e pressione Inserir, ou clique duas vezes nela, para pôr o endereço dela no cursor. Cada editor é dono do próprio diálogo, então dois editores numa página nunca compartilham uma seleção.
O que as expressões não fazem
Elas não escrevem nada, não chamam comandos de execução do Process, não guardam estado entre avaliações, não conseguem definir funções compartilhadas entre expressões, e não são avaliadas sob demanda: a varredura as publica a cada 100 ms e o editor mostra a prévia do rascunho duas vezes por segundo.