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.

Ver como Markdown

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 null nunca chega ao motor para virar 0.
  • 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.