# A cadeia de valor

> A conversão tipada que toda tag compartilha, da leitura bruta até o valor de engenharia, as duas políticas de leitura inválida, as ações fora de faixa, as transformações booleana e String, e como uma escrita reverte os estágios.

Toda tag compartilha uma única cadeia de conversão tipada que transforma a leitura bruta no valor de engenharia. A cadeia vive na própria tag: o cartão Conversão na página [Tags](connector-tags#the-conversion-card) e a grade do dispositivo mostram os mesmos estágios, e o valor que chega ao Logic, aos dashboards, ao gravador e ao que a estação publica é o que sai do último estágio. O nó OPC UA público carrega o valor bruto.

## O bruto primeiro {#raw-first}

A cadeia começa no **valor bruto** convertido para o tipo de dado da tag, e não no objeto do próprio driver: um driver que entrega 3,7 a uma tag Int32 lê 4 no topo do cartão, e todo estágio segue a partir desse 4. Uma leitura que o tipo declarado não consegue guardar de jeito nenhum (texto onde um número está declarado) é uma leitura vazia, nunca um zero de substituição. Os estágios calculam em números reais, e na outra ponta o valor de engenharia toma o seu tipo:

| Tag | Valor de engenharia |
| --- | --- |
| Tipo de dado inteiro, Escala e Calibração desligadas, ou ligadas com fator 1 e deslocamento 0 (como toda tag nasce) | O próprio número inteiro, no tipo de dado da tag. |
| Tipo de dado inteiro, Escala ou Calibração mudando o valor | Um número real (Double), arredondado pelo estágio Decimais: uma tag Int16 que guarda uma temperatura vezes dez lê 235 no dispositivo e 23,5 com escala 0,1. |
| Float ou Double | O tipo de dado da tag, então uma tag Float arredonda para o que um float consegue representar. |

O tipo de dado continua sendo o que o dispositivo e o nó OPC UA público carregam. Ligar ou desligar a Escala ou a Calibração muda o tipo do valor de engenharia dali em diante: o que o gravador já gravou fica como foi gravado, e um canal mantém o tipo que declara, então um canal Inteiro grava o valor arredondado para o inteiro mais próximo e um canal Número decimal mantém as casas decimais. O cartão Conversão fecha no valor entregue e avisa quando um tipo inteiro que a Escala e a Calibração deixam como está descarta, ao arredondar, as casas decimais de um limite que Limites usa para limitar o valor.

## Os estágios {#the-stages}

Nos tipos numéricos, a cadeia é uma sequência de estágios, cada um com a sua caixa de seleção; um estágio desligado repassa a entrada, e o cartão mostra o valor corrente ao fim de cada estágio, para que você acompanhe uma leitura ao vivo pela matemática:

| Estágio | Padrão | O que faz |
| --- | --- | --- |
| **Escala** | ligado | `escalado = bruto × Angular + Linear`. O Angular tem padrão 1, o Linear tem padrão 0. Um Angular igual a 0 é recusado onde é digitado ("Um fator de escala 0 zeraria toda leitura. Digite o fator pelo qual multiplicar (1 mantém o valor)."), porque zeraria toda leitura e a prévia e a cadeia persistida nunca podem discordar. |
| **Calibração** | desligado | Um segundo par linear aplicado ao valor escalado: `calibrado = escalado × Angular + Linear`. Fica separado da Escala para que um ajuste de como encontrado e como deixado não perturbe a matemática da faixa, e é protegido por permissão própria; veja [Calibração](connector-calibration). Um Angular igual a 0 é recusado do mesmo jeito. |
| **Leitura inválida** | sempre visível | Duas políticas para leituras que não trazem número aproveitável (abaixo). Não é uma caixa de seleção: o "desligado" dela é uma das próprias respostas. |
| **Limites** | desligado | Julga o valor contra **Mín** (padrão 0) e **Máx** (padrão 100) e aplica a ação escolhida para fora de faixa (abaixo). Os extremos são normalizados, então um Mín acima do Máx nunca falha: o menor dos dois é o piso. |
| **Decimais** | ligado | Arredonda conforme **Decimais**, padrão 2, aceito de 0 a 15. |

Os dois estágios lineares carregam um assistente **Dois pontos** que calcula o par a partir de dois pontos de referência; ele está descrito passo a passo em [Calibração](connector-calibration#the-two-point-assistant).

## O dispositivo respondeu sem um número {#the-device-answered-without-a-number}

Um termopar aberto, um canal sem sensor: a leitura chegou, o equipamento está conversando, mas a medição é NaN. Só em tags numéricas, e a qualidade continua boa nos dois casos:

| Política | Efeito |
| --- | --- |
| **Deixar passar** (padrão) | O NaN segue intocado e pula o estágio Limites por inteiro, seja qual for a ação daquele estágio: limites julgam números, e aqui não há nenhum. Infinito não é NaN e ainda satura na faixa. |
| **Substituir por um valor** | O número declarado assume deste estágio em diante e entra em Limites, Decimais e na conversão final como qualquer leitura. |

## O dispositivo não respondeu {#the-device-did-not-answer}

Um timeout, um cabo rompido, equipamento desligado, uma exceção do driver. Todos os tipos, embora
uma tag que lê texto, um carimbo de tempo, um identificador ou um bloco de bytes receba só as duas primeiras políticas:
um substituto declarado é um número, e uma leitura desses tipos não é um.

| Política | Efeito |
| --- | --- |
| **Mostrar o erro** (padrão) | A tag fica vazia e a qualidade dela vai a ruim, então a falha aparece em todo lugar de uma vez. |
| **Manter o último valor bom** | A última leitura que chegou continua exibida, sem prazo de validade, até o equipamento responder de novo. Os carimbos de tempo continuam apontando para aquela leitura, porque foi quando o número foi medido. Nada é mantido antes de a primeira leitura chegar; até lá a tag fica vazia. |
| **Substituir por um valor** | O número declarado é apresentado como foi declarado: não há leitura para percorrer os estágios, então ele não é escalado, calibrado nem arredondado, apenas convertido para o tipo do valor de engenharia. Oferecido nos tipos numéricos e no Booleano, cuja leitura pode sair de um número; não em String, DateTime, Guid nem ByteString. |

Um substituto nunca é silencioso: o cartão Valor ao vivo imprime o motivo ("Último valor bom, mantido enquanto o dispositivo não responde."), o ponto ao vivo fica âmbar, o servidor OPC UA embutido publica o valor com um status de substituição em vez de Good puro, e um agente que lê a tag com `tag_read` fica sabendo qual substituto é (`substitution`). Ele fica publicado enquanto a política pedir: um dispositivo que segue sem responder não faz um cliente externo alternar entre o substituto e uma falha de leitura, então o que aquele cliente lê é o que o painel mostra. A própria leitura retoma o ponto no instante em que o dispositivo responde, e desligar o substituto faz o mesmo. Escolher um substituto é escolher disponibilidade, então alarmes e expressões seguem julgando o ponto como se ele tivesse valor; o preço disso é pago às claras, porque o diário continua registrando a leitura que falhou e a saúde do dispositivo continua reportando o dispositivo offline. Um substituto responde "o que este ponto deve mostrar", nunca "o equipamento está aí". Uma substituição declarada fora dos limites habilitados recebe um alerta onde é digitada: "Fora dos limites (de 0 a 100): o valor que substitui uma leitura que falhou."

Uma leitura que cala vale como uma leitura que falhou. Quando nenhuma leitura nova chega durante o intervalo de leitura da tag mais 10 segundos, como quando um dispositivo aceita a conexão e depois para de responder, a política acima vale como se a leitura tivesse falhado, para tudo o que lê a tag: expressões da Logic, dashboards, o que é gravado e agentes. Com **Mostrar o erro** a tag fica vazia e a qualidade dela vai a ruim, enquanto o servidor OPC UA embutido mantém no nó o último valor do dispositivo com `UncertainLastUsableValue` em vez de Good, para que um cliente externo veja o número que tinha e saiba que nada o renova; com um substituto, o substituto é apresentado e publicado como acima. Os alarmes mantêm o estado enquanto a qualidade estiver ruim, como sempre. O cartão Valor ao vivo diz o motivo ("Nenhuma leitura nova chegou desde o carimbo de tempo do aplicativo. A tag conta isso como uma leitura que falhou."), os carimbos de tempo continuam datando a última leitura que chegou, e a próxima leitura que chegar traz a tag de volta.

Uma tag Somente escrita não tem nenhuma dessas políticas. A estação nunca a lê, então nenhuma leitura dela pode falhar: até a estação escrever nela, a tag não tem valor e diz isso, sem substituto, sem ponto âmbar e sem nada publicado no lugar dela pelo OPC UA, e o painel não desenha esta linha para ela. Uma política escolhida enquanto a tag era lida continua guardada e é ignorada enquanto a tag for Somente escrita; ela volta a valer assim que o acesso for Somente leitura ou Leitura e escrita.

## Valores fora de faixa {#out-of-range-values}

Ações de **Limites** para um valor fora do Mín e do Máx:

| Ação | O valor vira | Qualidade |
| --- | --- | --- |
| **Nulo** | Uma lacuna (sem valor). | boa |
| **Limitar** (padrão) | O extremo mais próximo. | boa |
| **Erro e nulo** | Uma lacuna. | ruim (falha de limite) |
| **Erro e limitar** | O extremo mais próximo. | ruim (falha de limite) |
| **NaN** | NaN. | boa. Oferecida só em tags Float e Double, cujo tipo consegue representá-lo; ela deixa um canal do Process classificar o valor inválido. Uma ação NaN deixada numa tag inteira por uma escrita de agente ou por um backup restaurado decai para a lacuna do Null. |

Uma falha de limite entra na qualidade efetiva da tag, então o ponto ao vivo, as expressões de propriedade e os alarmes enxergam o valor fora de limites como ruim sem nenhuma ligação extra, e o cartão Conversão imprime "O valor 130 está fora dos limites (de 0 a 100)." Ainda assim é uma condição de processo, não um problema de conexão, e a [saúde do dispositivo](connector-health) não conta o dispositivo como offline por causa dela.

## Booleano, String e outros tipos {#boolean-string-and-other-types}

Tipos não numéricos têm as suas transformações no mesmo cartão Conversão:

- **Booleano**: **Inverter** reporta a negação lógica do valor bruto.
- **String**: **Início do trecho** (base 0) e **Comprimento (vazio = até o fim)** recortam uma janela da cadeia bruta; um comprimento em branco vai até o fim, e extremos fora de faixa são aparados em vez de falhar.
- Todo outro tipo (DateTime, Guid, ByteString) passa sem mudança. O cartão Conversão dele traz só o estágio Leitura inválida, com a política para o dispositivo que não respondeu, e uma tag Somente escrita desses tipos não mostra cartão.

Mostrar o erro e manter o último valor bom valem para todo tipo; substituir por um valor é
oferecido só em tags numéricas e booleanas, então uma tag String, DateTime, Guid ou ByteString
não a lista. Uma substituição já guardada numa tag de um desses tipos, como uma versão anterior
podia gravá-la, é obedecida como mostrar o erro, e a próxima gravação da tag, pelo painel ou por
um agente, guarda mostrar o erro no lugar dela. A política de NaN vale só em tags numéricas.

## A escrita reverte a cadeia {#writes-reverse-the-pipeline}

O campo de escrita do cartão Valor ao vivo recebe um valor de engenharia e reverte, em ordem, os estágios habilitados que são inversíveis: apara no Mín e no Máx quando os Limites estão habilitados (uma escrita é sempre aparada, nunca descartada, seja qual for a ação de limite), descalibra (`(valor − Linear) ÷ Angular`), desescala do mesmo jeito e então converte para o tipo da tag. Uma tag inteira cuja Escala ou Calibração muda o valor aceita uma fração: 123,4 numa tag Int16 com escala 0,1 escreve 1234. Sem um estágio assim, uma fração escrita numa tag inteira é arredondada ao número inteiro mais próximo, e as metades vão para longe do zero (2,5 escreve 3). O arredondamento perde informação e não é revertido. Uma entrada booleana reaplica a Inversão. A subcadeia de String é só de exibição, então uma escrita de texto envia o valor inteiro tal como está; DateTime, Guid e ByteString passam sem mudança. Um valor escrito por um cliente OPC UA externo no nó público já é bruto e não atravessa nada disso.
