Estamos desenvolvendo um sistema supervisório de SMT, que lê o estado binário das luzes dos sinaleiros das máquinas usando um modbus.
Criei um Data Source “meta” que lê esses estados e reage de acordo com o horário do dia. O objetivo deste data source, é criar um temporizador (estilo cronômetro) na representação gráfica, que conta por quanto tempo aquele estado binário durou (ex: quanto tempo a luz AMARELA ficou em estado 1, até trocar para o estado 0). Ao trocar de estado, o temporizador deve ser pausado onde parou, retornando a contagem quando o estado é alterado novamente.
Estou com uma série de dificuldades na criação desse arranjo, mas uma das principais é que notei que, a cada execução do script no meu datapoint do DS Meta (que se atualiza em padrão Cron a cada 1 segundo), ele realiza input no BD do ScadaBR, na tabela “pointValues”. Não desejo este comportamento, uma vez que a execução do script deste data point não tem utilidade nenhuma para ficar armazenado em banco. Achei que sua execução era meramente em runtime, e fiquei surpreso de notar que há uma linha inputada por segundo no banco!
Como altero este comportamento? E caso não seja possível, qual seria a melhor abordagem para resolver meu problema na construção deste temporizador, sem acrescer novos dados ao banco (tendo em vista que o espaço de crescimento dele é limitado e de que esses dados gerados pelo temporizador não precisam ser armazenados, pois são descartados diariamente)?
Posso estar enganado, mas parece que por padrão o ScadaBR só atualiza o timestamp de um ponto quando há alteração de valor. Então, para um data point binário bastaria ler os últimos 2 timestamps e subtrair um do outro. Fica aí uma sugestão.
Olá Celso! De fato, é como estou trabalhando nessa questão. Porém, estou tendo que fazer via Data Source SQL consultando a tabela “pointValues” do próprio ScadaBR, pois não encontrei uma forma programaticamente eficiente de fazer por suas ferramentas internas, apenas.
Sabe como posso acessar o timestamp de um ponto binário em seu estado anterior ao atual via componente de Script Para o Servidor, por exemplo? Tentei usar as funções como “past” ou “ago”, mas nesta tela não tenho acesso, e mesmo assim não seria eficiente, pois preciso do timestamp anterior que pode ter acontecido a qualquer momento, não necessariamente há exatas 1 hora ou 1 dia atrás, por exemplo!
Olá Sidney, obrigado pela atenção! Caso precise de mais informações, estou a disposição.
Atualmente estou contingenciando a situação com uma procedure SQL que apaga as entradas no banco para os id’s destes Data Points, desta forma o tamanho do banco permanece controlado.
// Segundo em milissegundos
var segundo = 1000;
// Minuto em milissegundos
var minuto = 60 * segundo;
// Hora em milissegundos
var hora = 60 * minuto;
// Obter os últimos 2 valores do nosso datapoint
var valores = new com.serotonin.mango.db.dao.PointValueDao();
valores = valores.getLatestPointValues(point.id, 2);
var tempo_menor = valores.get(1).time;
var tempo_maior = valores.get(0).time;
var tempo = tempo_maior - tempo_menor;
// Convertendo o tempo para horas
var hh = parseInt(tempo / hora);
hh = (hh > 9) ? hh : ("0" + hh);
// Obtendo o resto
tempo %= hora;
// Convertendo o tempo para minutos
var mm = parseInt(tempo / minuto);
mm = (mm > 9) ? mm : ("0" + mm);
// Obtendo o resto
tempo %= minuto;
// Convertendo o tempo para segundos
var ss = parseInt(tempo / segundo);
ss = (ss > 9) ? ss : ("0" + ss);
// Retornando o tempo em que permaneceu ligado
if (value == true) {
return "<p class='queroCSS'>Ainda está ligado</p>";
} else {
return "<p class='queroCSS'>" + hh + ":" + mm + ":" + ss + "</p>";
}
Amigo, talvez você tenha salvo a minha vida! Eu conheço pouco sobre utilização direta das classes do MangoDB, tens algum link ou referência de documentação compatível com a versão usada pelo ScadaBR? Seria bastante útil, a julgar apenas por essa parte com.serotonin.mango.db.dao.PointValueDao().getLatestPointValues(point.id, 2);
Agradeço muito a contribuição!
PS: testarei sua sugestão amanhã ao início das minhas atividades e darei o retorno.
O código apresentado pelo Celso realiza o cálculo do horimetro e não salva no banco de dados, correto? Mas se eu precisar armazenar esse informação no banco para gerar um relatório, como poderia proceder a partir deste script?
Crie um Data source Virtual, inclua um ponto virtual numero para armazenar seu horímetro, sem atualização automática, configurável, com valor inicial zero, por exemplo.
Depois, crie um Data Source META para rodar o script que foi proposto acima, só que atualizando o valor deste datasource virtual que foi criado para registrar o horímetro. Cadatre o padrão de atualização (Cron, horario especifico, a cada minuto, etc) e toda vez no intervalo ajustado o script será executado e o valor do datapoint virtual será atualizado.
Funciona legal este método. eu utilizo este método para horímetro de ensaios onde eu coleto dados e valido estes dados comparando com critperios maior, menor, igual, etc, e então se os critérios forem atendidos eu somo 1 minuto no horímetro, e executo de minuto em minuto, no meu caso.
Pra ficar mais avançado ainda, dá pra criar datapoints virtuais com os critérios numéricos que o script vai utilizar para tomar decisão e comparação, e assim têm-se um script automático configuravel em um painel, por exemplo.
Ok. Muito obrigado Celso. Existe algum outro caminho? tentei fazer usando o Data Source Meta, porém para a variável que recebe o cálculo do horimetro, precisa estar configurada nas propriedades de renderização como periodo → hh:mm:ss. Desta forma ocorre um erro de offeset de 9 horas, por exemplo, vamos supor que o resultado do horímetro 56 segundos, o resultado obtido é 09:00:56. Não sei como corrigir esse erro de offset. Já viram algo parecido?
Tentei seguir a sua sugestão,para isso fui estudar aqui a questão da configuração do padrão Cron. Porém na hora que eu tento implementar no ScadaBR ,da erro da expressão. Para garantir a precisão do horímetro eu pensei em chamar o script a cada 30 segundos ( não sei se isso é viável tb, estou verificando), dai inseri a seguinte expressão Cron: 30 0 0 0 0 0. Porém da erro. Preciso informar mais alguma coisa? Minha expressão está incorreta?
Consegui implementar a função Cron, acabei encontrando este link aqui do forum: http://forum.scadabr.com.br/t/uso-do-cron-pattern/138/3 . Porém a rotina não funcionou. O que eu fiz foi utilizar o script do Celso e no return eu apenas inseri uma variável com o tempo calculado. Estou usando a versão 1.0 do ScadaBR. Qual versão você usa?
Após certa dificuldade, consegui adaptar o código do script para servidor para o datapoint Meta. Para criar um horímetro que registre o tempo que um datapoint binário ficou ligado e vá salvando esse valor, o código abaixo deve funcionar:
// ID do datapoint binário
var id = 4;
// Segundo em milissegundos
var segundo = 1000;
// Minuto em milissegundos
var minuto = 60 * segundo;
// Hora em milissegundos
var hora = 60 * minuto;
// Dia em milissegundos
var dia = 24 * hora;
// Obter os últimos 2 valores do nosso datapoint
var valores = new com.serotonin.mango.db.dao.PointValueDao();
valores = valores.getLatestPointValues(id, 2);
var mais_antigo = valores.get(1);
var mais_recente = valores.get(0);
// Armazenar tempo em milissegundos numa variável
var tempo = 0;
if (String(mais_recente.value) == "true") {
// Equipamento ligado, contar o tempo
var tempo_atual = new Date().getTime(); // Usar o relógio do PC
tempo = tempo_atual - mais_recente.time;
} else {
// Equipamento desligado, pegar o tempo que ficou ligado
tempo = mais_recente.time - mais_antigo.time;
}
// Converter o tempo de milissegundos para um formato legível
// Convertendo o tempo para dias
var dd = parseInt(tempo / hora);
// Obtendo o resto
tempo %= dia;
// Convertendo o tempo para horas
var hh = parseInt(tempo / hora);
hh = (hh > 9) ? hh : ("0" + hh);
// Obtendo o resto
tempo %= hora;
// Convertendo o tempo para minutos
var mm = parseInt(tempo / minuto);
mm = (mm > 9) ? mm : ("0" + mm);
// Obtendo o resto
tempo %= minuto;
// Convertendo o tempo para segundos
var ss = parseInt(tempo / segundo);
ss = (ss > 9) ? ss : ("0" + ss);
// Tudo feito, retornar o tempo em que permaneceu ligado
return dd + " dia(s) " + hh + "h " + mm + "min " + ss + "s";
A imagem abaixo mostra como eu configurei o datapoint Meta (note que é necessário alterar o ID do datapoint manualmente no código):
Por fim, tenho uma observação: como o Alan mencionou no primeiro post desse tópico, esse horímetro vai salvar um valor no banco de dados toda vez que o script for executado (o que pode gastar muito espaço caso você o configure para rodar com uma frequência alta). Isso talvez possa ser minimizado reduzindo o período dos dados que o ScadaBR mantém para o histórico desse datapoint, mas não tenho certeza porque não entendo praticamente nada de banco de dados.
Criei o Data Source Meta com o nome HORIMETRO, em seguida criei um data point com o seu script, o id do datapoint binario é referente ao datapoint do data source TCP/IP que no meu caso é o número 4.
Parece que está dando um “estouro” no array porque o código está procurando os últimos 2 valores e não existe valor nenhum no histórico do ponto. Cuidado para não confundir o ID do data point com o Offset (endereço Modbus) do data point, são coisas diferentes.