305 lines
11 KiB
C#
305 lines
11 KiB
C#
using AgroBase.Models;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO.Ports;
|
|
using System.Linq;
|
|
using System.Windows.Forms;
|
|
using System.Threading.Tasks;
|
|
using static AgroBase.Models.Enums;
|
|
|
|
namespace AgroBase.Services
|
|
{
|
|
public class PZEMService
|
|
{
|
|
public static bool Iniciado { get; set; }
|
|
public static int TaxaAmostragem { get; set; } = 500;
|
|
public static byte slaveAddress = 0x01;
|
|
|
|
public static PZEMModel UltimaLeitura = new PZEMModel();
|
|
public static PZEMModel PenultimaLeitura = new PZEMModel();
|
|
public static double TensaoMinima { get; set; } = 36.0;
|
|
public static double TensaoMaxima { get; set; } = 42.0;
|
|
public static double CorrenteMax { get; set; } = 20.0;
|
|
public static bool ModoLeitura = false;
|
|
|
|
|
|
public static Dictionary<string, byte> CodigosFuncoes = new Dictionary<string, byte>()
|
|
{
|
|
{ "LeituraParametro", 0x03 },
|
|
{ "AquisicaoDados", 0x04 },
|
|
{ "GravacaoParametro", 0x06 },
|
|
{ "ResetEnergia", 0x42 },
|
|
{ "ErroGravaParametro", 0x86 },
|
|
{ "Calibrar", 0x41 },
|
|
{ "ErroCalibrar", 0xC1 },
|
|
};
|
|
public static Dictionary<string, byte> Parametros = new Dictionary<string, byte>()
|
|
{
|
|
{ "AlarmeTensaoMaxima", 0x0000 },
|
|
{ "AlarmeTensaoMinima", 0x0001 },
|
|
{ "EnderecoRTU", 0x0002 },
|
|
{ "EscalaCorrenteAtual", 0x0003 },
|
|
};
|
|
public static CoulombCounterService ContadorCarga = new CoulombCounterService(CorrenteMax);
|
|
|
|
|
|
public static async Task<bool> VerificaPortaPZEM(SerialPort porta)
|
|
{
|
|
ModbusService.DefinirPortaCOM(porta);
|
|
|
|
var Comando = new ModbusComandoModel()
|
|
{
|
|
Dispositivo = T_Code.Pzm,
|
|
Endereco = slaveAddress,
|
|
Comando = ComandoAquisicaoDados(),
|
|
Verificacao = true,
|
|
TamanhoEsperado = 16
|
|
};
|
|
|
|
ModbusService.AdicionarComandoNaFila(Comando);
|
|
|
|
while (Comando.RespondidoEm == DateTime.MinValue)
|
|
{
|
|
await Task.Delay(200);
|
|
}
|
|
|
|
Iniciado = DecifrarRespostaAquisicao(Comando.Resposta);
|
|
|
|
if (Iniciado)
|
|
{
|
|
DefinirDispositivo();
|
|
return Iniciado;
|
|
}
|
|
|
|
if (!ModbusService.Iniciado)
|
|
{
|
|
ModbusService.LimparDadosPorta();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static void DefinirDispositivo()
|
|
{
|
|
if (Iniciado)
|
|
{
|
|
SerialService.DispositivosMapeados.Add(new DispositivoDetalhesModel()
|
|
{
|
|
Endereco = ModbusService._PortaModbus.PortName,
|
|
Dispositivo = T_Code.Pzm,
|
|
Erro = !Iniciado,
|
|
Versao = "17"
|
|
});
|
|
}
|
|
}
|
|
|
|
public static bool DecifrarRespostaAquisicao(byte[] resposta)
|
|
{
|
|
try
|
|
{
|
|
if (!resposta.Any() || resposta.Length < 16)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (resposta[1] == CodigosFuncoes["AquisicaoDados"])
|
|
{
|
|
int numBytes = resposta[2];
|
|
if (numBytes == 16) // Se o número de bytes de dados for 16
|
|
{
|
|
PZEMModel modelo = new PZEMModel()
|
|
{
|
|
DataHora = DateTime.Now,
|
|
};
|
|
var tensao_raw = "0x" + resposta[3].ToString("X") + resposta[4].ToString("X");
|
|
modelo.Tensao = Convert.ToInt32(tensao_raw, 16) * 0.02; // 0.01;
|
|
var corrente_raw = "0x" + resposta[5].ToString("X") + resposta[6].ToString("X");
|
|
modelo.Corrente = Convert.ToInt32(corrente_raw, 16) * 0.002; // 0.0015;
|
|
var potencia_raw = "0x" + resposta[7].ToString("X") + resposta[8].ToString("X") + resposta[9].ToString("X") + resposta[10].ToString("X");
|
|
modelo.Potencia = Convert.ToInt32(potencia_raw, 16) * 0.0001; // 0.1;
|
|
var energia_raw = "0x" + resposta[11].ToString("X") + resposta[12].ToString("X") + resposta[13].ToString("X") + resposta[14].ToString("X");
|
|
modelo.Energia = Convert.ToInt32(energia_raw, 16) * 1.0;
|
|
var almMax_raw = "0x" + resposta[15].ToString("X") + resposta[16].ToString("X");
|
|
modelo.AlarmeTensaoMax = almMax_raw == "0xFFFF";
|
|
var almMin_raw = "0x" + resposta[17].ToString("X") + resposta[18].ToString("X");
|
|
modelo.AlarmeTensaoMin = almMin_raw == "0xFFFF";
|
|
|
|
UltimaLeitura = modelo;
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Número de bytes de dados não esperado.");
|
|
}
|
|
}
|
|
else if (resposta[1] == CodigosFuncoes["LeituraParametro"])
|
|
{
|
|
var parametro_raw = "0x" + resposta[3].ToString("X") + resposta[4].ToString("X");
|
|
double Valor = Convert.ToInt16(parametro_raw, 16) * 0.01;
|
|
if (ModoLeitura)
|
|
{
|
|
MessageBox.Show("Valor do parâmetro: " + Valor);
|
|
}
|
|
}
|
|
else if (resposta[1] == CodigosFuncoes["GravacaoParametro"])
|
|
{
|
|
MessageBox.Show("Parâmetro gravado com sucesso!");
|
|
}
|
|
else if (resposta[1] == CodigosFuncoes["ErroGravaParametro"])
|
|
{
|
|
MessageBox.Show("Erro ao gravar parâmetro!");
|
|
}
|
|
else if (resposta[1] == CodigosFuncoes["Calibrar"])
|
|
{
|
|
MessageBox.Show("Calibragem do PZEM-017 finalizada com sucesso!");
|
|
}
|
|
else if (resposta[1] == CodigosFuncoes["ErroCalibrar"])
|
|
{
|
|
MessageBox.Show("Erro ao calibrar o PZEM-017!");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Resposta inválida ou código de função incorreto.");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static bool ProcessarResposta(byte[] Resposta)
|
|
{
|
|
PenultimaLeitura = new PZEMModel()
|
|
{
|
|
AlarmeTensaoMax = UltimaLeitura.AlarmeTensaoMax,
|
|
AlarmeTensaoMin = UltimaLeitura.AlarmeTensaoMin,
|
|
Corrente = UltimaLeitura.Corrente,
|
|
DataHora = UltimaLeitura.DataHora,
|
|
Energia = UltimaLeitura.Energia,
|
|
Potencia = UltimaLeitura.Potencia,
|
|
Tensao = UltimaLeitura.Tensao
|
|
};
|
|
|
|
bool Sucesso = DecifrarRespostaAquisicao(Resposta);
|
|
|
|
ContadorCarga.AtualizarConsumo();
|
|
|
|
Variaveis.OperacaoEmAndamento.Sensoriamento.BateriaConsumida = Math.Round(ContadorCarga.PercentualConsumido, 2);
|
|
Variaveis.OperacaoEmAndamento.Sensoriamento.PorcentagemBateria = Math.Round(FuncoesMatematicas.Map(UltimaLeitura.Tensao, TensaoMinima, TensaoMaxima, 0.0, 100.0), 2);
|
|
if (Variaveis.OperacaoEmAndamento.DispSen != null)
|
|
{
|
|
Variaveis.OperacaoEmAndamento.DispSen.Dados.BateriaCargaConsumida = ContadorCarga.ConsumidoAmp;
|
|
}
|
|
|
|
return Sucesso;
|
|
}
|
|
|
|
#region Comandos
|
|
|
|
public static byte[] ComandoAquisicaoDados()
|
|
{
|
|
byte functionCode = CodigosFuncoes["AquisicaoDados"];
|
|
ushort startAddress = 0x0000;
|
|
ushort numOfRegisters = 0x0008;
|
|
|
|
List<byte> command = new List<byte>();
|
|
command.Add(slaveAddress);
|
|
command.Add(functionCode);
|
|
command.AddRange(BitConverter.GetBytes(startAddress).Reverse()); // Big endian
|
|
command.AddRange(BitConverter.GetBytes(numOfRegisters).Reverse()); // Big endian
|
|
|
|
byte[] crc = ModbusService.Crc16(command.ToArray()); // Supondo que você tenha a implementação do CRC16
|
|
command.AddRange(crc);
|
|
|
|
return command.ToArray();
|
|
}
|
|
|
|
public static byte[] ComandoSetParametro(byte Parametro, float valor)
|
|
{
|
|
// Convertendo o valor para o formato correto (LSB = 0.01)
|
|
int valorInt = (int)(valor * 100); // Convertendo para inteiro conforme a resolução
|
|
byte functionCode = CodigosFuncoes["GravacaoParametro"];
|
|
ushort registerAddress = Parametro;
|
|
|
|
// Construindo o comando
|
|
List<byte> command = new List<byte>();
|
|
command.Add(slaveAddress);
|
|
command.Add(functionCode);
|
|
command.AddRange(BitConverter.GetBytes(registerAddress).Reverse()); // Little endian
|
|
command.AddRange(BitConverter.GetBytes((ushort)valorInt).Reverse()); // Little endian
|
|
|
|
byte[] crc = ModbusService.Crc16(command.ToArray()); // Supondo que você tenha a implementação do CRC16
|
|
command.AddRange(crc);
|
|
|
|
return command.ToArray();
|
|
}
|
|
|
|
public static byte[] ComandoGetParametro(byte Parametro)
|
|
{
|
|
byte functionCode = CodigosFuncoes["LeituraParametro"];
|
|
ushort registerAddress = Parametro;
|
|
ushort numberOfRegisters = 0x0001; // Lendo apenas um registro
|
|
|
|
// Construindo o comando
|
|
List<byte> command = new List<byte>();
|
|
command.Add(slaveAddress);
|
|
command.Add(functionCode);
|
|
command.AddRange(BitConverter.GetBytes(registerAddress).Reverse()); // Big endian
|
|
command.AddRange(BitConverter.GetBytes(numberOfRegisters).Reverse()); // Big endian
|
|
|
|
byte[] crc = ModbusService.Crc16(command.ToArray()); // Supondo que você tenha a implementação do CRC16
|
|
command.AddRange(crc);
|
|
|
|
return command.ToArray();
|
|
}
|
|
|
|
public static byte[] ComandoResetEnergia()
|
|
{
|
|
// Código de função específico para reset de energia
|
|
byte functionCode = CodigosFuncoes["ResetEnergia"];
|
|
|
|
// Construindo o comando
|
|
List<byte> command = new List<byte>();
|
|
command.Add(slaveAddress);
|
|
command.Add(functionCode);
|
|
|
|
// Adicionando o CRC ao comando
|
|
byte[] crc = ModbusService.Crc16(command.ToArray()); // Supondo que você tenha a implementação do CRC16
|
|
command.AddRange(crc);
|
|
|
|
return command.ToArray();
|
|
}
|
|
|
|
public static byte[] ComandoCalibragem()
|
|
{
|
|
byte functionCode = CodigosFuncoes["Calibrar"];
|
|
|
|
// Bytes fixos para o comando de calibragem
|
|
byte[] bytesComando = new byte[] { 0xF8, functionCode, 0x37, 0x21 };
|
|
|
|
// Calculando o CRC para os bytes do comando
|
|
byte[] crc = ModbusService.Crc16(bytesComando);
|
|
|
|
// Adicionando o CRC ao comando
|
|
List<byte> comandoCalibragem = new List<byte>(bytesComando);
|
|
comandoCalibragem.AddRange(crc);
|
|
|
|
return comandoCalibragem.ToArray();
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
}
|