6171 lines
245 KiB
C#
6171 lines
245 KiB
C#
using AgroBase.Comum;
|
|
using AgroBase.Forms.Operacoes;
|
|
using AgroBase.Models.Modules;
|
|
using AgroBase.Models.Operacoes;
|
|
using AgroBase.Models.Operadores;
|
|
using AgroBase.Services;
|
|
using AgroBase.Services.Operadores;
|
|
using AgroMonitor;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using static AgroBase.Models.Enums;
|
|
using static AgroBase.Services.OIDCanService.OidHandler;
|
|
|
|
namespace AgroBase.Models
|
|
{
|
|
public class OperacaoModel
|
|
{
|
|
#region TIMERS
|
|
|
|
public double tmrLeiturasInterval
|
|
{
|
|
get
|
|
{
|
|
return tmrLeituras?.Interval ?? 500;
|
|
}
|
|
set
|
|
{
|
|
tmrLeituras?.SetInterval((int)value);
|
|
}
|
|
}
|
|
private AsyncTaskTimerModel tmrLeituras;
|
|
private AsyncTaskTimerModel tmrComunicacao;
|
|
public void IniciarTimersSistema()
|
|
{
|
|
if (!Variaveis.IsAgroBase)
|
|
return;
|
|
|
|
if (!ReferenceEquals(Variaveis.OperacaoEmAndamento, this))
|
|
{
|
|
Variaveis.MostrarLog(
|
|
$"[OperacaoModel.IniciarTimersSistema] Ignorado: instância não é atual. " +
|
|
$"Hash={GetHashCode()}, AtualHash={Variaveis.OperacaoEmAndamento?.GetHashCode()}"
|
|
);
|
|
return;
|
|
}
|
|
|
|
tmrLeituras?.Stop();
|
|
tmrLeituras?.Dispose();
|
|
tmrLeituras = new AsyncTaskTimerModel($"tmrLeitura_{GetHashCode()}", tmrLeituras_Tick, 500);
|
|
tmrLeituras.Start();
|
|
|
|
tmrComunicacao?.Stop();
|
|
tmrComunicacao?.Dispose();
|
|
tmrComunicacao = new AsyncTaskTimerModel($"tmrComunicacao_{GetHashCode()}", tmrComunicacao_Tick, 1000);
|
|
tmrComunicacao.Start();
|
|
|
|
Variaveis.MostrarLog(
|
|
$"[OperacaoModel.IniciarTimersSistema] Timers iniciados. Hash={GetHashCode()}, Modo={Parametros?.Modo}"
|
|
);
|
|
}
|
|
public void PararTimersSistema()
|
|
{
|
|
try
|
|
{
|
|
tmrLeituras?.Stop();
|
|
tmrLeituras?.Dispose();
|
|
tmrLeituras = null;
|
|
|
|
tmrComunicacao?.Stop();
|
|
tmrComunicacao?.Dispose();
|
|
tmrComunicacao = null;
|
|
|
|
Variaveis.MostrarLog(
|
|
$"[OperacaoModel.PararTimersSistema] Timers do sistema parados. Operacao={ID}, Hash={GetHashCode()}, idxLog={idxLog}"
|
|
);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel.PararTimersSistema] Erro ao parar timers do sistema: " + ex.Message);
|
|
}
|
|
}
|
|
|
|
|
|
public double tmrLogsInterval
|
|
{
|
|
get
|
|
{
|
|
return _tmrLogsOperacao?.Interval ?? 1000;
|
|
}
|
|
set
|
|
{
|
|
_tmrLogsOperacao?.SetInterval((int)value);
|
|
}
|
|
}
|
|
private AsyncTaskTimerModel _tmrLogsOperacao;
|
|
private int idxLog = 0;
|
|
private readonly SemaphoreSlim _salvarLogsGate = new SemaphoreSlim(1, 1);
|
|
private void IniciarTimerLogsOperacao()
|
|
{
|
|
if (!Variaveis.IsAgroBase)
|
|
return;
|
|
|
|
_tmrLogsOperacao?.Stop();
|
|
_tmrLogsOperacao?.Dispose();
|
|
|
|
_tmrLogsOperacao = new AsyncTaskTimerModel($"tmrLogs_{ID}", tmrLogs_Tick, 1000);
|
|
|
|
_tmrLogsOperacao.Start();
|
|
|
|
Variaveis.MostrarLog($"[OperacaoModel.IniciarTimerLogsOperacao] Timer de logs iniciado. Operacao={ID}, Hash={GetHashCode()}");
|
|
}
|
|
private void PararTimerLogsOperacao()
|
|
{
|
|
try
|
|
{
|
|
_tmrLogsOperacao?.Stop();
|
|
|
|
Variaveis.MostrarLog($"[OperacaoModel.PararTimerLogsOperacao] Timer de logs parado. Operacao={ID}, Hash={GetHashCode()}, idxLog={idxLog}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel.PararTimerLogsOperacao] Erro ao parar timer de logs: " + ex.Message);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
public StatusModulo Status { get; set; }
|
|
public string Descricao { get; set; }
|
|
public string OprPath { get; set; }
|
|
public OperacaoControleModel Controle { get; set; } = new OperacaoControleModel();
|
|
public OperacaoControleModel ControleAnterior { get; set; } = new OperacaoControleModel();
|
|
public DispositivosService<MovimentacaoUnificadaModel> DispMvd { get; set; }
|
|
public DispositivosService<SensoriamentoModel> DispSen { get; set; }
|
|
public DispositivosService<AtuadorModel> DispAtu { get; set; }
|
|
public MapasModel Mapa { get; set; } = new MapasModel();
|
|
public TrajetoriaMapaOperacaoModel Trajetoria { get; set; }
|
|
public List<GPSModel> GPSTrajetoria { get; set; } = new List<GPSModel>();
|
|
public OperacaoParametrosModel Parametros { get; set; } = new OperacaoParametrosModel();
|
|
public OperacaoSensoriamentoConjuntoModel Sensoriamento { get; set; }
|
|
|
|
private readonly object _sensoriamentoStateLock = new object();
|
|
internal void DefinirEstadoCalibragemRuntime(bool calibrando, bool pausa)
|
|
{
|
|
lock (_sensoriamentoStateLock)
|
|
{
|
|
if (Sensoriamento?.Operacao != null)
|
|
{
|
|
Sensoriamento.Operacao.Calibrando = calibrando;
|
|
Sensoriamento.Operacao.Pausa = pausa;
|
|
}
|
|
}
|
|
|
|
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("calibrando", calibrando));
|
|
}
|
|
internal void SubstituirSensoriamentoSnapshot(OperacaoSensoriamentoConjuntoModel dadosAtualizados)
|
|
{
|
|
if (dadosAtualizados == null)
|
|
return;
|
|
|
|
lock (_sensoriamentoStateLock)
|
|
{
|
|
var runtime = Sensoriamento?.Operacao;
|
|
|
|
if (runtime != null && dadosAtualizados.Operacao != null)
|
|
{
|
|
dadosAtualizados.Operacao.CopiarEstadoRuntimeDe(runtime);
|
|
}
|
|
|
|
Sensoriamento = dadosAtualizados;
|
|
}
|
|
}
|
|
internal void MarcarModuloCalibrado(T_Code modulo, string id, bool ok)
|
|
{
|
|
lock (_sensoriamentoStateLock)
|
|
{
|
|
if (Sensoriamento?.Operacao?.ModsCalibragem == null)
|
|
{
|
|
Sensoriamento.Operacao.ModsCalibragem =
|
|
new Dictionary<T_Code, Dictionary<string, bool>>();
|
|
}
|
|
|
|
if (!Sensoriamento.Operacao.ModsCalibragem.ContainsKey(modulo) ||
|
|
Sensoriamento.Operacao.ModsCalibragem[modulo] == null)
|
|
{
|
|
Sensoriamento.Operacao.ModsCalibragem[modulo] =
|
|
new Dictionary<string, bool>();
|
|
}
|
|
|
|
Sensoriamento.Operacao.ModsCalibragem[modulo][id] = ok;
|
|
}
|
|
}
|
|
internal bool ModuloEstaCalibrado(T_Code modulo, string id)
|
|
{
|
|
lock (_sensoriamentoStateLock)
|
|
{
|
|
var mods = Sensoriamento?.Operacao?.ModsCalibragem;
|
|
|
|
if (mods == null)
|
|
return false;
|
|
|
|
if (!mods.TryGetValue(modulo, out var itens) || itens == null)
|
|
return false;
|
|
|
|
return itens.TryGetValue(id, out bool ok) && ok;
|
|
}
|
|
}
|
|
|
|
|
|
private readonly object _eventosLock = new object();
|
|
private readonly List<OperacaoSensoriamentoLogErrosModel> _eventosPendentes = new List<OperacaoSensoriamentoLogErrosModel>();
|
|
private readonly Dictionary<string, DateTime> _dedupeEventosRecentes = new Dictionary<string, DateTime>();
|
|
private static readonly TimeSpan JanelaDedupeEvento = TimeSpan.FromSeconds(2);
|
|
private static string CriarChaveEvento(T_Code dispositivo, StatusModulo status, double saude, string mensagem, string id, string condicoes)
|
|
{
|
|
return string.Join(
|
|
"|",
|
|
dispositivo,
|
|
id ?? "",
|
|
status,
|
|
Math.Round(saude, 3).ToString(CultureInfo.InvariantCulture),
|
|
mensagem ?? "",
|
|
condicoes ?? ""
|
|
);
|
|
}
|
|
internal void InserirEventoOperacao(T_Code dispositivo, StatusModulo status, double saude, string mensagem, string id = null, string condicoes = null)
|
|
{
|
|
try
|
|
{
|
|
DateTime agora = DateTime.Now;
|
|
|
|
string chave = CriarChaveEvento(
|
|
dispositivo,
|
|
status,
|
|
saude,
|
|
mensagem,
|
|
id,
|
|
condicoes
|
|
);
|
|
|
|
lock (_eventosLock)
|
|
{
|
|
var expirados = _dedupeEventosRecentes
|
|
.Where(x => agora - x.Value > JanelaDedupeEvento)
|
|
.Select(x => x.Key)
|
|
.ToList();
|
|
|
|
foreach (var key in expirados)
|
|
_dedupeEventosRecentes.Remove(key);
|
|
|
|
if (_dedupeEventosRecentes.TryGetValue(chave, out DateTime ultimo) && agora - ultimo <= JanelaDedupeEvento)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_dedupeEventosRecentes[chave] = agora;
|
|
|
|
_eventosPendentes.Add(new OperacaoSensoriamentoLogErrosModel()
|
|
{
|
|
Momento = agora,
|
|
Dispositivo = dispositivo,
|
|
ID = id,
|
|
Status = status,
|
|
Saude = saude,
|
|
Mensagem = mensagem,
|
|
Condicoes = condicoes
|
|
});
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Variaveis.MostrarLog($"[OperacaoModel.InserirEventoOperacao] Erro ao inserir evento: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
|
|
private readonly object _atualizarDadosLock = new object();
|
|
internal void AtualizarSensoriamentoSeguro()
|
|
{
|
|
lock (_atualizarDadosLock)
|
|
{
|
|
Sensoriamento?.AtualizarDados();
|
|
}
|
|
}
|
|
|
|
|
|
public Form frmOperacao { get; set; }
|
|
|
|
public bool Treinando { get; set; } = false;
|
|
public bool Simulando { get; set; } = false;
|
|
public double SimulacaoAnguloControle { get; set; } = 0;
|
|
public double SimulacaoRpmControle { get; set; } = 0;
|
|
|
|
public int TempoIniciarOperacao { get; set; } = 10;
|
|
public string ID { get; set; }
|
|
|
|
private static string _discoverySessionId = Guid.NewGuid().ToString("N");
|
|
private static long _telemetrySequence = 0;
|
|
private readonly SemaphoreSlim _calibragemGate = new SemaphoreSlim(1, 1);
|
|
public bool CalibrandoRuntime
|
|
{
|
|
get
|
|
{
|
|
lock (_sensoriamentoStateLock)
|
|
return Sensoriamento?.Operacao?.Calibrando == true;
|
|
}
|
|
}
|
|
private DateTime _ultimaTentativaCalibragem = DateTime.MinValue;
|
|
private readonly TimeSpan _cooldownCalibragem = TimeSpan.FromSeconds(30);
|
|
private bool PodeTentarCalibragemAutomatica()
|
|
{
|
|
return DateTime.Now - _ultimaTentativaCalibragem > _cooldownCalibragem;
|
|
}
|
|
private void RegistrarTentativaCalibragem()
|
|
{
|
|
_ultimaTentativaCalibragem = DateTime.Now;
|
|
}
|
|
internal List<OperacaoSensoriamentoLogErrosModel> DrenarEventosPendentes()
|
|
{
|
|
lock (_eventosLock)
|
|
{
|
|
var eventos = _eventosPendentes
|
|
.Where(x => x != null)
|
|
.OrderBy(x => x.Momento)
|
|
.ToList();
|
|
|
|
_eventosPendentes.Clear();
|
|
|
|
return eventos;
|
|
}
|
|
}
|
|
internal List<OperacaoSensoriamentoLogErrosModel> ListarEventosPendentes()
|
|
{
|
|
lock (_eventosLock)
|
|
{
|
|
return _eventosPendentes
|
|
.Where(x => x != null)
|
|
.OrderBy(x => x.Momento)
|
|
.ToList();
|
|
}
|
|
}
|
|
internal void ReenfileirarEventosPendentes(List<OperacaoSensoriamentoLogErrosModel> eventos)
|
|
{
|
|
if (eventos == null || eventos.Count == 0)
|
|
return;
|
|
|
|
lock (_eventosLock)
|
|
{
|
|
_eventosPendentes.InsertRange(0, eventos.Where(x => x != null));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#region PARAMETRIZACAO
|
|
|
|
private bool EhOperacaoAtual(string origem)
|
|
{
|
|
if (ReferenceEquals(Variaveis.OperacaoEmAndamento, this))
|
|
return true;
|
|
|
|
Variaveis.MostrarLog(
|
|
$"[OperacaoModel.{origem}] Ignorado: instância não é atual. " +
|
|
$"Hash={GetHashCode()}, AtualHash={Variaveis.OperacaoEmAndamento?.GetHashCode()}, ID={ID}, AtualID={Variaveis.OperacaoEmAndamento?.ID}"
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
public bool CarregarParametrizacaoOperacao(Panel pnlMapa, Label lblMapa, string opPath = "")
|
|
{
|
|
if (Variaveis.OperacaoEmAndamento?.Sensoriamento?.Operacao?.OperacaoIniciada == true)
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel.CarregarParametrizacaoOperacao] Ignorado: tentativa de carregar operação com operação iniciada.");
|
|
return false;
|
|
}
|
|
|
|
string path = Variaveis.CaminhoSistema + Variaveis.CaminhoOperacoes + MapasVariaveisModel.NomeArquivoMapaInterativoSaida;
|
|
|
|
OpenFileDialog openFileDialog = new OpenFileDialog();
|
|
openFileDialog.Filter = "Arquivo de Operação (*.opr)|*.opr";
|
|
openFileDialog.DefaultExt = "opr";
|
|
openFileDialog.AddExtension = true;
|
|
openFileDialog.InitialDirectory = Variaveis.CaminhoSistema + Variaveis.CaminhoOperacoes;
|
|
if (!string.IsNullOrEmpty(opPath) || openFileDialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
string opr_path = !string.IsNullOrEmpty(opPath) ? opPath : openFileDialog.FileName;
|
|
|
|
if (!File.Exists(opr_path)) return false;
|
|
|
|
string ParametrosJson = File.ReadAllText(opr_path, Encoding.UTF8);
|
|
|
|
var Parametros = JsonConvert.DeserializeObject<OperacaoParametrosModel>(ParametrosJson);
|
|
|
|
if (Parametros.Modo == null) return false;
|
|
|
|
var newOp = CarregarParametrosOperacaoPadrao((ModoOperacao)Parametros.Modo, CarregarModulos: true);
|
|
|
|
newOp.Parametros = Parametros;
|
|
newOp.DefinirComponentesEmUso();
|
|
|
|
newOp.Descricao = Parametros.Descricao;
|
|
newOp.OprPath = opr_path;
|
|
if (newOp.DispSen == null)
|
|
{
|
|
newOp.DispSen = new DispositivosService<SensoriamentoModel>();
|
|
}
|
|
|
|
Variaveis.OperacaoEmAndamento = newOp;
|
|
|
|
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("configurado", false));
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static OperacaoModel CarregarParametrosOperacaoPadrao(ModoOperacao Modo, bool CarregarModulos)
|
|
{
|
|
OperacaoModel op = new OperacaoModel()
|
|
{
|
|
Simulando = false,
|
|
GPSTrajetoria = new List<GPSModel>(),
|
|
Mapa = new MapasModel(),
|
|
Trajetoria = new TrajetoriaMapaOperacaoModel(new List<List<GPSModel>>()),
|
|
ControleAnterior = new OperacaoControleModel(),
|
|
Parametros = new OperacaoParametrosModel()
|
|
{
|
|
Modo = Modo,
|
|
Descricao = $"{Modo} - Padrão",
|
|
QtdCamerasSolo = VariaveisEquipamento.QuantidadeCamerasSolo,
|
|
QtdBicos = VariaveisEquipamento.QuantidadeBicosPulverizadores,
|
|
CapacidadeReservatorio = VariaveisEquipamento.CapacidadeReservatorio,
|
|
RoverId = VariaveisEquipamento.Parametros.serial_number,
|
|
IP = VariaveisEquipamento.Parametros.rover_ip,
|
|
RuasPercorrer = null,
|
|
Mapa = null,
|
|
PontosRetorno = null,
|
|
DadosLeitura = new OperacaoParametrosDadosModel(),
|
|
ModulosMandatorios = new List<OperacaoModulosMandatoriosModel>()
|
|
{
|
|
new OperacaoModulosMandatoriosModel() { Dispositivo = T_Code.Npc, Mandatorio = true, Utilizar = true },
|
|
new OperacaoModulosMandatoriosModel() { Dispositivo = T_Code.Can, Mandatorio = true, Utilizar = true },
|
|
new OperacaoModulosMandatoriosModel() { Dispositivo = T_Code.Bat, Mandatorio = true, Utilizar = true },
|
|
}
|
|
}
|
|
};
|
|
op.Sensoriamento = new OperacaoSensoriamentoConjuntoModel(op)
|
|
{
|
|
Operacao = new OperacaoSensoriamentoLogModel()
|
|
{
|
|
OperacaoIniciada = false,
|
|
DataInicio = DateTime.MinValue,
|
|
DataFim = DateTime.MinValue
|
|
}
|
|
};
|
|
|
|
if (CarregarModulos)
|
|
{
|
|
var SenConectado = (DispositivosService<SensoriamentoModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == T_Code.Sen);
|
|
var AtuConectado = (DispositivosService<AtuadorModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == T_Code.Atu);
|
|
var MvdConectado = (DispositivosService<MovimentacaoUnificadaModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == T_Code.Mvd);
|
|
|
|
op.DispSen = SenConectado;
|
|
op.DispAtu = AtuConectado;
|
|
op.DispMvd = MvdConectado;
|
|
}
|
|
|
|
switch (Modo)
|
|
{
|
|
case ModoOperacao.NaoDefinido:
|
|
|
|
break;
|
|
case ModoOperacao.Manual:
|
|
op.Parametros.Controle = new OperacaoParametrosControleModel()
|
|
{
|
|
RegistrarDadosPosProcessamento = false,
|
|
|
|
MovimentoAutomatico = false,
|
|
DirecionalAutomatico = false,
|
|
PulverizadorAutomatico = false,
|
|
|
|
FrenagemAutomaticaAoParar = false,
|
|
ImuParadaPorInclinacao = false,
|
|
ImuAuxilioMovimento = false,
|
|
ImuAuxilioDirecional = false,
|
|
ImuDirecionalPreferirArco = false,
|
|
OakParadaPorObstaculo = false,
|
|
DirAuxilioSonar = false,
|
|
MovAuxilioSonar = false,
|
|
MpcHorizonte = 4.0,
|
|
AnteciparManobraCorredorM = 0,
|
|
|
|
MovVelocidadeSErvasPercent = 35,
|
|
MovVelocidadeCErvasPercent = 12,
|
|
DirAnguloMaximo = 30,
|
|
DirVelocidadeMovimento = 40,
|
|
|
|
DirTipoMovimento = TiposControladorDirecional.Manual,
|
|
|
|
AtuAlturaAreaPulverizacao = 10,
|
|
AtuDuracaoAtuacao = 200,
|
|
AtuPercentualErvasBicoOff = 2,
|
|
AtuPercentualErvasBicoOn = 1,
|
|
AtuPercentualInicioPulverizacao = 85,
|
|
AtuPressaoLinha = 22,
|
|
AtuAgitadorModo = ModoAgitadorCalda.SemAgitacao,
|
|
AtuModoControle = ModoControleBomba.PID
|
|
};
|
|
op.Parametros.ModulosMandatorios.AddRange(new List<OperacaoModulosMandatoriosModel>()
|
|
{
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Mov,
|
|
Mandatorio = false,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Dir,
|
|
Mandatorio = false,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Atu,
|
|
Mandatorio = false,
|
|
Utilizar = true,
|
|
}
|
|
});
|
|
op.Parametros.ParametrosMandatorios = new List<OperacaoParametrosMandatoriosModel>()
|
|
{
|
|
new OperacaoParametrosMandatoriosModel()
|
|
{
|
|
Parametro = ParametrosOperacao.Joystick,
|
|
Mandatorio = false,
|
|
Utilizar = true,
|
|
},
|
|
};
|
|
op.Controle = new OperacaoControleModel()
|
|
{
|
|
TipoMovimento = TipoMovimentoDirecional.RodasDianteiras,
|
|
Angulo = 0,
|
|
EmFreio = false,
|
|
PercentualVelocidadeSP = 0,
|
|
AlturaBarra = 50,
|
|
TiposControle = new List<OperacaoControleTipoModel>()
|
|
{
|
|
new OperacaoControleTipoModel()
|
|
{
|
|
Tipo = T_Code.Mov,
|
|
DelayEnvioComandoBase = 10,
|
|
DelayEnvioComando = 250,
|
|
DelayEnvioComandoExtra = 0,
|
|
Comandos = new List<string>(),
|
|
UltimoComando = DateTime.Now,
|
|
DirecaoAtual = Direcao.Parado,
|
|
UltimaDirecao = Direcao.Parado
|
|
},
|
|
new OperacaoControleTipoModel()
|
|
{
|
|
Tipo = T_Code.Dir,
|
|
DelayEnvioComandoBase = 10,
|
|
DelayEnvioComando = 250,
|
|
DelayEnvioComandoExtra = 0,
|
|
Comandos = new List<string>(),
|
|
UltimoComando = DateTime.Now,
|
|
DirecaoAtual = Direcao.Parado,
|
|
UltimaDirecao = Direcao.Parado
|
|
},
|
|
new OperacaoControleTipoModel()
|
|
{
|
|
Tipo = T_Code.Atu,
|
|
DelayEnvioComandoBase = 10,
|
|
DelayEnvioComando = 10,
|
|
DelayEnvioComandoExtra = 0,
|
|
Comandos = new List<string>(),
|
|
UltimoComando = DateTime.Now
|
|
},
|
|
},
|
|
};
|
|
if (CarregarModulos)
|
|
op.frmOperacao = new frmOperacaoManual();
|
|
break;
|
|
case ModoOperacao.MapaGPS:
|
|
op.Parametros.Controle = new OperacaoParametrosControleModel()
|
|
{
|
|
RegistrarDadosPosProcessamento = false,
|
|
|
|
MovimentoAutomatico = true,
|
|
DirecionalAutomatico = true,
|
|
PulverizadorAutomatico = true,
|
|
|
|
FrenagemAutomaticaAoParar = true,
|
|
ImuParadaPorInclinacao = true,
|
|
ImuAuxilioMovimento = true,
|
|
ImuAuxilioDirecional = true,
|
|
ImuDirecionalPreferirArco = true,
|
|
OakParadaPorObstaculo = true,
|
|
DirAuxilioSonar = true,
|
|
MovAuxilioSonar = true,
|
|
MpcHorizonte = 4.0,
|
|
AnteciparManobraCorredorM = 10.0,
|
|
|
|
MovVelocidadeSErvasPercent = 50,
|
|
MovVelocidadeCErvasPercent = 20,
|
|
DirAnguloMaximo = 30,
|
|
DirVelocidadeMovimento = 50,
|
|
|
|
DirTipoMovimento = TiposControladorDirecional.MPC,
|
|
|
|
AtuAlturaAreaPulverizacao = 10,
|
|
AtuDuracaoAtuacao = 200,
|
|
AtuPercentualErvasBicoOff = 2,
|
|
AtuPercentualErvasBicoOn = 1,
|
|
AtuPercentualInicioPulverizacao = 85,
|
|
AtuPressaoLinha = 22,
|
|
AtuAgitadorModo = ModoAgitadorCalda.Continuo,
|
|
AtuModoControle = ModoControleBomba.PID,
|
|
};
|
|
op.Parametros.ModulosMandatorios.AddRange(new List<OperacaoModulosMandatoriosModel>()
|
|
{
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Ipb,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Mov,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Dir,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Sen,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Atu,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Gps,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Cam,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Snr,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
});
|
|
op.Parametros.ParametrosMandatorios = new List<OperacaoParametrosMandatoriosModel>()
|
|
{
|
|
new OperacaoParametrosMandatoriosModel()
|
|
{
|
|
Parametro = ParametrosOperacao.Mapa,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
};
|
|
op.Controle = new OperacaoControleModel()
|
|
{
|
|
TipoMovimento = TipoMovimentoDirecional.RodasDianteiras,
|
|
Angulo = 0,
|
|
EmFreio = false,
|
|
PercentualVelocidadeSP = 0,
|
|
AlturaBarra = 50,
|
|
TiposControle = new List<OperacaoControleTipoModel>()
|
|
{
|
|
new OperacaoControleTipoModel()
|
|
{
|
|
Tipo = T_Code.Mov,
|
|
DelayEnvioComandoBase = 500,
|
|
DelayEnvioComando = 500,
|
|
DelayEnvioComandoExtra = 0,
|
|
Comandos = new List<string>(),
|
|
UltimoComando = DateTime.Now,
|
|
DirecaoAtual = Direcao.Parado,
|
|
UltimaDirecao = Direcao.Parado
|
|
},
|
|
new OperacaoControleTipoModel()
|
|
{
|
|
Tipo = T_Code.Dir,
|
|
DelayEnvioComandoBase = 300,
|
|
DelayEnvioComando = 300,
|
|
DelayEnvioComandoExtra = 0,
|
|
Comandos = new List<string>(),
|
|
UltimoComando = DateTime.Now,
|
|
DirecaoAtual = Direcao.Parado,
|
|
UltimaDirecao = Direcao.Parado
|
|
},
|
|
new OperacaoControleTipoModel()
|
|
{
|
|
Tipo = T_Code.Atu,
|
|
DelayEnvioComandoBase = 200,
|
|
DelayEnvioComando = 200,
|
|
DelayEnvioComandoExtra = 0,
|
|
Comandos = new List<string>(),
|
|
UltimoComando = DateTime.Now
|
|
},
|
|
},
|
|
};
|
|
if (CarregarModulos)
|
|
op.frmOperacao = new frmOperacaoMapaGPS();
|
|
break;
|
|
case ModoOperacao.TreinamentoIA:
|
|
op.Parametros.Controle = new OperacaoParametrosControleModel()
|
|
{
|
|
RegistrarDadosPosProcessamento = false,
|
|
|
|
MovimentoAutomatico = true,
|
|
DirecionalAutomatico = true,
|
|
PulverizadorAutomatico = false,
|
|
|
|
FrenagemAutomaticaAoParar = false,
|
|
ImuParadaPorInclinacao = false,
|
|
ImuAuxilioMovimento = false,
|
|
ImuAuxilioDirecional = false,
|
|
ImuDirecionalPreferirArco = false,
|
|
OakParadaPorObstaculo = false,
|
|
DirAuxilioSonar = false,
|
|
MovAuxilioSonar = false,
|
|
MpcHorizonte = 4.0,
|
|
AnteciparManobraCorredorM = 0,
|
|
|
|
MovVelocidadeSErvasPercent = 50,
|
|
MovVelocidadeCErvasPercent = 20,
|
|
DirAnguloMaximo = 30,
|
|
DirVelocidadeMovimento = 50,
|
|
DirTipoMovimento = TiposControladorDirecional.IA,
|
|
|
|
AtuAlturaAreaPulverizacao = 10,
|
|
AtuDuracaoAtuacao = 200,
|
|
AtuPercentualErvasBicoOff = 2,
|
|
AtuPercentualErvasBicoOn = 1,
|
|
AtuPercentualInicioPulverizacao = 70,
|
|
AtuPressaoLinha = 22,
|
|
AtuAgitadorModo = ModoAgitadorCalda.SemAgitacao,
|
|
AtuModoControle = ModoControleBomba.PID,
|
|
};
|
|
op.Parametros.ModulosMandatorios.AddRange(new List<OperacaoModulosMandatoriosModel>()
|
|
{
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Mov,
|
|
Mandatorio = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Dir,
|
|
Mandatorio = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Atu,
|
|
Mandatorio = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Gps,
|
|
Mandatorio = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Sen,
|
|
Mandatorio = false,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Wit,
|
|
Mandatorio = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Pzm,
|
|
Mandatorio = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Lra,
|
|
Mandatorio = true,
|
|
}
|
|
});
|
|
op.Parametros.ParametrosMandatorios = new List<OperacaoParametrosMandatoriosModel>()
|
|
{
|
|
new OperacaoParametrosMandatoriosModel()
|
|
{
|
|
Parametro = ParametrosOperacao.CameraSolo,
|
|
Mandatorio = true,
|
|
},
|
|
new OperacaoParametrosMandatoriosModel()
|
|
{
|
|
Parametro = ParametrosOperacao.Sonar,
|
|
Mandatorio = true,
|
|
},
|
|
new OperacaoParametrosMandatoriosModel()
|
|
{
|
|
Parametro = ParametrosOperacao.Mapa,
|
|
Mandatorio = true,
|
|
}
|
|
};
|
|
op.Controle = new OperacaoControleModel()
|
|
{
|
|
TipoMovimento = TipoMovimentoDirecional.RodasDianteiras,
|
|
Angulo = 0,
|
|
EmFreio = false,
|
|
PercentualVelocidadeSP = 0,
|
|
TiposControle = new List<OperacaoControleTipoModel>()
|
|
{
|
|
new OperacaoControleTipoModel()
|
|
{
|
|
Tipo = T_Code.Mov,
|
|
DelayEnvioComandoBase = 500,
|
|
DelayEnvioComando = 500,
|
|
DelayEnvioComandoExtra = 0,
|
|
Comandos = new List<string>(),
|
|
UltimoComando = DateTime.Now,
|
|
DirecaoAtual = Direcao.Parado,
|
|
UltimaDirecao = Direcao.Parado
|
|
},
|
|
new OperacaoControleTipoModel()
|
|
{
|
|
Tipo = T_Code.Dir,
|
|
DelayEnvioComandoBase = 1000,
|
|
DelayEnvioComando = 1000,
|
|
DelayEnvioComandoExtra = 0,
|
|
Comandos = new List<string>(),
|
|
UltimoComando = DateTime.Now,
|
|
DirecaoAtual = Direcao.Parado,
|
|
UltimaDirecao = Direcao.Parado
|
|
},
|
|
new OperacaoControleTipoModel()
|
|
{
|
|
Tipo = T_Code.Atu,
|
|
DelayEnvioComandoBase = 500,
|
|
DelayEnvioComando = 500,
|
|
DelayEnvioComandoExtra = 0,
|
|
Comandos = new List<string>(),
|
|
UltimoComando = DateTime.Now
|
|
},
|
|
},
|
|
};
|
|
break;
|
|
case ModoOperacao.MapeamentoVisual:
|
|
op.Parametros.Controle = new OperacaoParametrosControleModel()
|
|
{
|
|
RegistrarDadosPosProcessamento = false,
|
|
|
|
MovimentoAutomatico = true,
|
|
DirecionalAutomatico = true,
|
|
PulverizadorAutomatico = false,
|
|
|
|
FrenagemAutomaticaAoParar = true,
|
|
ImuParadaPorInclinacao = true,
|
|
ImuAuxilioMovimento = true,
|
|
ImuAuxilioDirecional = true,
|
|
ImuDirecionalPreferirArco = true,
|
|
OakParadaPorObstaculo = true,
|
|
DirAuxilioSonar = true,
|
|
MovAuxilioSonar = true,
|
|
MpcHorizonte = 4.0,
|
|
AnteciparManobraCorredorM = 10.0,
|
|
|
|
MovVelocidadeSErvasPercent = 40,
|
|
MovVelocidadeCErvasPercent = 20,
|
|
DirAnguloMaximo = 30,
|
|
DirVelocidadeMovimento = 50,
|
|
|
|
DirTipoMovimento = TiposControladorDirecional.PID,
|
|
|
|
AtuAlturaAreaPulverizacao = 10,
|
|
AtuDuracaoAtuacao = 200,
|
|
AtuPercentualErvasBicoOff = 2,
|
|
AtuPercentualErvasBicoOn = 1,
|
|
AtuPercentualInicioPulverizacao = 85,
|
|
AtuPressaoLinha = 22,
|
|
AtuAgitadorModo = ModoAgitadorCalda.SemAgitacao,
|
|
AtuModoControle = ModoControleBomba.PID,
|
|
};
|
|
op.Parametros.ModulosMandatorios.AddRange(new List<OperacaoModulosMandatoriosModel>()
|
|
{
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Ipb,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Mov,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Dir,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
}
|
|
});
|
|
op.Parametros.ParametrosMandatorios = new List<OperacaoParametrosMandatoriosModel>()
|
|
{
|
|
new OperacaoParametrosMandatoriosModel()
|
|
{
|
|
Parametro = ParametrosOperacao.Sonar,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
}
|
|
};
|
|
op.Controle = new OperacaoControleModel()
|
|
{
|
|
TipoMovimento = TipoMovimentoDirecional.RodasDianteiras,
|
|
Angulo = 0,
|
|
EmFreio = false,
|
|
PercentualVelocidadeSP = 0,
|
|
TiposControle = new List<OperacaoControleTipoModel>()
|
|
{
|
|
new OperacaoControleTipoModel()
|
|
{
|
|
Tipo = T_Code.Mov,
|
|
DelayEnvioComandoBase = 500,
|
|
DelayEnvioComando = 500,
|
|
DelayEnvioComandoExtra = 0,
|
|
Comandos = new List<string>(),
|
|
UltimoComando = DateTime.Now,
|
|
DirecaoAtual = Direcao.Parado,
|
|
UltimaDirecao = Direcao.Parado
|
|
},
|
|
new OperacaoControleTipoModel()
|
|
{
|
|
Tipo = T_Code.Dir,
|
|
DelayEnvioComandoBase = 200,
|
|
DelayEnvioComando = 200,
|
|
DelayEnvioComandoExtra = 0,
|
|
Comandos = new List<string>(),
|
|
UltimoComando = DateTime.Now,
|
|
DirecaoAtual = Direcao.Parado,
|
|
UltimaDirecao = Direcao.Parado
|
|
}
|
|
},
|
|
};
|
|
break;
|
|
case ModoOperacao.RetornoBase:
|
|
op.Parametros.Controle = new OperacaoParametrosControleModel()
|
|
{
|
|
RegistrarDadosPosProcessamento = false,
|
|
|
|
MovimentoAutomatico = true,
|
|
DirecionalAutomatico = true,
|
|
PulverizadorAutomatico = false,
|
|
|
|
FrenagemAutomaticaAoParar = true,
|
|
ImuParadaPorInclinacao = true,
|
|
ImuAuxilioMovimento = true,
|
|
ImuAuxilioDirecional = true,
|
|
ImuDirecionalPreferirArco = true,
|
|
OakParadaPorObstaculo = true,
|
|
DirAuxilioSonar = true,
|
|
MovAuxilioSonar = true,
|
|
MpcHorizonte = 4.0,
|
|
AnteciparManobraCorredorM = 0,
|
|
|
|
MovVelocidadeSErvasPercent = 60,
|
|
MovVelocidadeCErvasPercent = 20,
|
|
DirAnguloMaximo = 30,
|
|
DirVelocidadeMovimento = 50,
|
|
|
|
DirTipoMovimento = TiposControladorDirecional.MPC,
|
|
|
|
AtuAlturaAreaPulverizacao = 10,
|
|
AtuDuracaoAtuacao = 200,
|
|
AtuPercentualErvasBicoOff = 2,
|
|
AtuPercentualErvasBicoOn = 1,
|
|
AtuPercentualInicioPulverizacao = 85,
|
|
AtuPressaoLinha = 22,
|
|
AtuAgitadorModo = ModoAgitadorCalda.SemAgitacao,
|
|
AtuModoControle = ModoControleBomba.PID,
|
|
};
|
|
op.Parametros.ModulosMandatorios.AddRange(new List<OperacaoModulosMandatoriosModel>()
|
|
{
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Ipb,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Mov,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Dir,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Sen,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Atu,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Gps,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
new OperacaoModulosMandatoriosModel()
|
|
{
|
|
Dispositivo = T_Code.Snr,
|
|
Mandatorio = true,
|
|
Utilizar = true,
|
|
},
|
|
});
|
|
op.Parametros.ParametrosMandatorios = new List<OperacaoParametrosMandatoriosModel>();
|
|
op.Controle = new OperacaoControleModel()
|
|
{
|
|
TipoMovimento = TipoMovimentoDirecional.RodasDianteiras,
|
|
Angulo = 0,
|
|
EmFreio = false,
|
|
PercentualVelocidadeSP = 0,
|
|
AlturaBarra = 50,
|
|
TiposControle = new List<OperacaoControleTipoModel>()
|
|
{
|
|
new OperacaoControleTipoModel()
|
|
{
|
|
Tipo = T_Code.Mov,
|
|
DelayEnvioComandoBase = 500,
|
|
DelayEnvioComando = 500,
|
|
DelayEnvioComandoExtra = 0,
|
|
Comandos = new List<string>(),
|
|
UltimoComando = DateTime.Now,
|
|
DirecaoAtual = Direcao.Parado,
|
|
UltimaDirecao = Direcao.Parado
|
|
},
|
|
new OperacaoControleTipoModel()
|
|
{
|
|
Tipo = T_Code.Dir,
|
|
DelayEnvioComandoBase = 300,
|
|
DelayEnvioComando = 300,
|
|
DelayEnvioComandoExtra = 0,
|
|
Comandos = new List<string>(),
|
|
UltimoComando = DateTime.Now,
|
|
DirecaoAtual = Direcao.Parado,
|
|
UltimaDirecao = Direcao.Parado
|
|
},
|
|
},
|
|
};
|
|
break;
|
|
|
|
}
|
|
|
|
op.Parametros.ModulosMandatorios.ForEach(m => m.ComponentesEmUso = op.PreencherComponentesEmUso(m.Dispositivo));
|
|
if (CarregarModulos)
|
|
{
|
|
op.DefinirComponentesEmUso();
|
|
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("configurado", false));
|
|
op.AtualizarSensoriamentoSeguro();
|
|
}
|
|
|
|
return op;
|
|
}
|
|
|
|
private Dictionary<string, (bool, bool)> PreencherComponentesEmUso(T_Code Modulo)
|
|
{
|
|
var op = this;
|
|
|
|
Dictionary<string, (bool, bool)> d = new Dictionary<string, (bool, bool)>();
|
|
switch (Modulo)
|
|
{
|
|
case T_Code.Mov:
|
|
var dadosMov = op?.DispMvd?.Dados ?? MovimentacaoUnificadaModel.CarregarParametrosIniciais();
|
|
dadosMov?.Modulos?.ForEach(m => d.Add(m.Modulo_ID, (true, m.MovMotor.Comandar)));
|
|
break;
|
|
case T_Code.Dir:
|
|
var dadosDir = op?.DispMvd?.Dados ?? MovimentacaoUnificadaModel.CarregarParametrosIniciais();
|
|
dadosDir?.Modulos?.ForEach(m => d.Add(m.Modulo_ID, (true, m.DirMotor.Comandar)));
|
|
break;
|
|
case T_Code.Atu:
|
|
var dadosAtu = op?.DispAtu?.Dados ?? AtuadorModel.CarregarParametrosIniciais();
|
|
dadosAtu?.Sensores?.ForEach(s => d.Add(s.ID, (s.Mandatorio, s.Aferir)));
|
|
dadosAtu?.BombasPressurizadoras?.ForEach(b => d.Add(b.ID, (b.Mandatorio, b.Comandar)));
|
|
dadosAtu?.BicosPulverizadores?.ForEach(b => d.Add(b.ID, (b.Mandatorio, b.Comandar)));
|
|
break;
|
|
case T_Code.Sen:
|
|
var dadosSen = op?.DispSen?.Dados ?? SensoriamentoModel.CarregarParametrosIniciais();
|
|
dadosSen?.Sensores?.ForEach(s => d.Add(s.ID, (s.Mandatorio, s.Aferir)));
|
|
dadosSen?.Sinaleiros?.ForEach(s => d.Add(s.ID, (s.Mandatorio, s.Controlar)));
|
|
dadosSen?.Servos?.ForEach(s => d.Add(s.ID, (s.Mandatorio, s.Controlar)));
|
|
dadosSen?.Reles?.ForEach(r => d.Add(r.ID, (r.Mandatorio, r.Controlar)));
|
|
break;
|
|
}
|
|
return d;
|
|
}
|
|
|
|
private void DefinirComponentesEmUso()
|
|
{
|
|
var op = this;
|
|
|
|
op.Parametros.ModulosMandatorios?.ForEach(m =>
|
|
{
|
|
var comp = m.ComponentesEmUso ?? new Dictionary<string, (bool, bool)>();
|
|
switch (m.Dispositivo)
|
|
{
|
|
case T_Code.Mov:
|
|
foreach (var c in comp)
|
|
{
|
|
var d = op.DispMvd?.Dados?.Modulos?.FirstOrDefault(x => x?.Modulo_ID == c.Key)?.MovMotor;
|
|
if (d != null)
|
|
d.Comandar = c.Value.Item2;
|
|
}
|
|
break;
|
|
case T_Code.Dir:
|
|
foreach (var c in comp)
|
|
{
|
|
var d = op.DispMvd?.Dados?.Modulos?.FirstOrDefault(x => x?.Modulo_ID == c.Key)?.DirMotor;
|
|
if (d != null)
|
|
d.Comandar = c.Value.Item2;
|
|
}
|
|
break;
|
|
case T_Code.Atu:
|
|
var da = op.DispAtu?.Dados;
|
|
foreach (var c in comp)
|
|
{
|
|
var s = da?.Sensores?.FirstOrDefault(x => x.ID == c.Key);
|
|
if (s != null)
|
|
{
|
|
s.Mandatorio = c.Value.Item1;
|
|
s.Aferir = c.Value.Item2;
|
|
continue;
|
|
}
|
|
var bc = da?.BicosPulverizadores?.FirstOrDefault(x => x.ID == c.Key);
|
|
if (bc != null)
|
|
{
|
|
bc.Mandatorio = c.Value.Item1;
|
|
bc.Comandar = c.Value.Item2;
|
|
continue;
|
|
}
|
|
var bo = da?.BombasPressurizadoras?.FirstOrDefault(x => x.ID == c.Key);
|
|
if (bo != null)
|
|
{
|
|
bo.Mandatorio = c.Value.Item1;
|
|
bo.Comandar = c.Value.Item2;
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
case T_Code.Sen:
|
|
var ds = op.DispSen?.Dados;
|
|
foreach (var c in comp)
|
|
{
|
|
var s = ds?.Sensores?.FirstOrDefault(x => x.ID == c.Key);
|
|
if (s != null)
|
|
{
|
|
s.Mandatorio = c.Value.Item1;
|
|
s.Aferir = c.Value.Item2;
|
|
continue;
|
|
}
|
|
var sv = ds?.Servos?.FirstOrDefault(x => x.ID == c.Key);
|
|
if (sv != null)
|
|
{
|
|
sv.Mandatorio = c.Value.Item1;
|
|
sv.Controlar = c.Value.Item2;
|
|
continue;
|
|
}
|
|
var rl = ds?.Reles?.FirstOrDefault(x => x.ID == c.Key);
|
|
if (rl != null)
|
|
{
|
|
rl.Mandatorio = c.Value.Item1;
|
|
rl.Controlar = c.Value.Item2;
|
|
continue;
|
|
}
|
|
var ld = ds?.Sinaleiros?.FirstOrDefault(x => x.ID == c.Key);
|
|
if (ld != null)
|
|
{
|
|
ld.Mandatorio = c.Value.Item1;
|
|
ld.Controlar = c.Value.Item2;
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
public static OperacaoModel CarregarParamerosOperacaoBase(OperacaoParametrosModel parametros)
|
|
{
|
|
if (parametros?.Modo == null)
|
|
return null;
|
|
|
|
var novaOp = CarregarParametrosOperacaoPadrao((ModoOperacao)parametros.Modo, CarregarModulos: true);
|
|
|
|
novaOp.Descricao = parametros.Descricao;
|
|
novaOp.OprPath = "";
|
|
|
|
novaOp.Parametros.Descricao = parametros.Descricao;
|
|
novaOp.Parametros.CapacidadeReservatorio = parametros.CapacidadeReservatorio;
|
|
novaOp.Parametros.Controle = parametros.Controle;
|
|
novaOp.Parametros.QtdBicos = parametros.QtdBicos;
|
|
novaOp.Parametros.QtdCamerasSolo = parametros.QtdCamerasSolo;
|
|
novaOp.Parametros.TipoMapa = parametros.TipoMapa;
|
|
novaOp.Parametros.Mapa = parametros.Mapa;
|
|
novaOp.Parametros.RuasPercorrer = parametros.RuasPercorrer;
|
|
novaOp.Parametros.PontosRetorno = parametros.PontosRetorno;
|
|
novaOp.Parametros.ModulosMandatorios = parametros.ModulosMandatorios;
|
|
novaOp.Parametros.ParametrosMandatorios = parametros.ParametrosMandatorios;
|
|
|
|
novaOp.DefinirComponentesEmUso();
|
|
|
|
Variaveis.OperacaoEmAndamento = novaOp;
|
|
|
|
var ruasSelecionadas = parametros.RuasPercorrer ?? new List<string>();
|
|
|
|
if (parametros.Mapa != null)
|
|
{
|
|
novaOp.Mapa = new MapasModel() { RuasPercorrer = ruasSelecionadas };
|
|
novaOp.Mapa.TipoMapa = novaOp.Parametros.TipoMapa;
|
|
novaOp.Mapa.PopularTrajetoriaMapa(parametros.Mapa);
|
|
}
|
|
|
|
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("configurado", false));
|
|
|
|
return novaOp;
|
|
}
|
|
|
|
|
|
public async Task IniciarOperacao()
|
|
{
|
|
if (!EhOperacaoAtual(nameof(IniciarOperacao)))
|
|
return;
|
|
|
|
var op = this;
|
|
|
|
if (op.Sensoriamento?.Operacao?.OperacaoIniciada == true)
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel.IniciarOperacao] Ignorado: operação já iniciada.");
|
|
return;
|
|
}
|
|
|
|
DateTime agora = DateTime.Now;
|
|
var dispSen = op.DispSen;
|
|
var dispAtu = op.DispAtu;
|
|
var dispMvd = op.DispMvd;
|
|
|
|
op.Simulando = false;
|
|
op.Treinando = false;
|
|
|
|
op.Sensoriamento.Operacao.OperacaoIniciada = true;
|
|
op.Sensoriamento.Operacao.Emergencia = false;
|
|
op.Sensoriamento.Operacao.Pausa = false;
|
|
op.Sensoriamento.Operacao.DataInicio = agora;
|
|
op.Sensoriamento.Operacao.DataFim = DateTime.MinValue;
|
|
|
|
op.ID = op.Sensoriamento.Operacao.DataInicio.ToString("dd_MM_yyyy_HH_mm_ss") + "_" + (op.Parametros?.Modo ?? ModoOperacao.NaoDefinido).ToString();
|
|
Directory.CreateDirectory(Variaveis.CaminhoOperacoes + op.ID + "/");
|
|
|
|
op.SalvarOperacao();
|
|
|
|
op.AtualizarSensoriamentoSeguro();
|
|
|
|
dispMvd?.Dados?.ReiniciarLeituras(dispMvd?.Dados);
|
|
dispAtu?.Dados?.ReiniciarLeituras(dispAtu?.Dados);
|
|
dispSen?.Dados?.ReiniciarLeituras(dispSen?.Dados);
|
|
dispAtu?.Dados?.PrepararAtuadorParaOperacao();
|
|
|
|
op.Sensoriamento.Operacao.ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>()
|
|
{
|
|
{ T_Code.Mov, new Dictionary<string, bool>() { } },
|
|
{ T_Code.Dir, new Dictionary<string, bool>() { } },
|
|
{ T_Code.Atu, new Dictionary<string, bool>() { } },
|
|
};
|
|
|
|
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("configurado", false));
|
|
WeedWorkerService.ReiniciarLeituraAnalise();
|
|
VisualWorkerService.ReiniciarLeituraAnalise();
|
|
|
|
op.Controle.Reiniciar();
|
|
op.DefinirTipoMovimentoControle(TipoMovimentoDirecional.RodasDianteiras);
|
|
op.ControleAnterior.Reiniciar();
|
|
|
|
double distanciaPercorrida = dispMvd?.Dados?.DistanciaPercorridaTotal ?? 0;
|
|
double tempoAtuado = dispAtu?.Dados?.TempoAtuado ?? 0;
|
|
dispSen?.Dados?.ContadorCarga?.AtualizarConsumo(distanciaPercorrida);
|
|
dispSen?.Dados?.ContadorCarga?.IniciarOperacao(distanciaPercorrida);
|
|
dispAtu?.Dados?.ContadorCarga?.IniciarOperacao(distanciaPercorrida, tempoAtuado);
|
|
|
|
op.GPSTrajetoria = new List<GPSModel>();
|
|
|
|
op.Trajetoria?.ProjetarTrajetoriaFixa();
|
|
op.Trajetoria.VerificacaoInicialMeioRuaConcluida = false;
|
|
|
|
op.Sensoriamento.UltimoRegistroLog = agora;
|
|
op.idxLog = 0;
|
|
op.IniciarTimerLogsOperacao();
|
|
|
|
await op.RealizarCalibragemInicialAsync(true);
|
|
|
|
RedisService.Publish(CmdKey.ManagerWorkerRx, JsonConvert.SerializeObject(new { cmd = ManagerWorkerCommandType.IniciarMPC } ));
|
|
}
|
|
|
|
public async Task FinalizarOperacao()
|
|
{
|
|
var op = this;
|
|
|
|
if (!EhOperacaoAtual(nameof(FinalizarOperacao)))
|
|
return;
|
|
|
|
if (op.Sensoriamento.Operacao.Finalizando)
|
|
return;
|
|
|
|
if (op.Sensoriamento?.Operacao?.OperacaoIniciada != true)
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel.FinalizarOperacao] Ignorado: operação não iniciada.");
|
|
return;
|
|
}
|
|
|
|
op.Sensoriamento.Operacao.Finalizando = true;
|
|
|
|
op.Trajetoria?.LoopAtualizaDados();
|
|
|
|
await Task.Delay(2000);
|
|
|
|
op.Sensoriamento.Operacao.OperacaoIniciada = false;
|
|
op.Sensoriamento.Operacao.Emergencia = false;
|
|
op.Sensoriamento.Operacao.Calibrando = false;
|
|
op.Sensoriamento.Operacao.Pausa = false;
|
|
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("calibrando", false));
|
|
|
|
op.Sensoriamento.Operacao.DataFim = DateTime.Now;
|
|
|
|
op.PararTimerLogsOperacao();
|
|
|
|
await op.SalvarLogsSeguroAsync(true);
|
|
|
|
op.Sensoriamento.Operacao.Finalizando = false;
|
|
op.Trajetoria?.AutonomiaCorredor?.Parar();
|
|
op.DispSen?.Dados?.ContadorCarga?.FinalizarOperacao();
|
|
op.DispAtu?.Dados?.ContadorCarga?.FinalizarOperacao();
|
|
|
|
if (op.Parametros.Modo == ModoOperacao.RetornoBase)
|
|
{
|
|
var new_op = CarregarParametrosOperacaoPadrao(ModoOperacao.MapaGPS, CarregarModulos: false);
|
|
op.Parametros = new_op.Parametros;
|
|
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("configurado", false));
|
|
}
|
|
}
|
|
|
|
public void ReiniciarOperacao(bool daBase)
|
|
{
|
|
if (!EhOperacaoAtual(nameof(ReiniciarOperacao)))
|
|
return;
|
|
|
|
var op = this;
|
|
|
|
RedisService.AtualizarCampos(
|
|
CtxKey.DadosOperacao,
|
|
("status", StatusOperacao.Parametrizando),
|
|
("iniciado", false)
|
|
);
|
|
|
|
var novaOp = CarregarParamerosOperacaoBase(op.Parametros);
|
|
|
|
if (novaOp == null)
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel.ReiniciarOperacao] Falha ao recriar operação.");
|
|
return;
|
|
}
|
|
|
|
if (daBase)
|
|
novaOp.EnviarParametorsOperacao();
|
|
}
|
|
|
|
public async Task IniciarSimulacao()
|
|
{
|
|
if (!EhOperacaoAtual(nameof(IniciarSimulacao)))
|
|
return;
|
|
|
|
var op = this;
|
|
var dispSen = op.DispSen;
|
|
var dispAtu = op.DispAtu;
|
|
var dispMvd = op.DispMvd;
|
|
|
|
op.Simulando = true;
|
|
op.Treinando = false;
|
|
|
|
op.Sensoriamento.Operacao.OperacaoIniciada = true;
|
|
op.Sensoriamento.Operacao.DataInicio = DateTime.Now;
|
|
op.Sensoriamento.Operacao.DataFim = DateTime.MinValue;
|
|
|
|
op.ID = "";
|
|
|
|
op.AtualizarSensoriamentoSeguro();
|
|
|
|
dispMvd?.Dados?.ReiniciarLeituras(dispMvd.Dados);
|
|
dispAtu?.Dados?.ReiniciarLeituras(dispAtu.Dados);
|
|
dispSen?.Dados?.ReiniciarLeituras(dispSen.Dados);
|
|
|
|
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("configurado", false));
|
|
WeedWorkerService.ReiniciarLeituraAnalise();
|
|
VisualWorkerService.ReiniciarLeituraAnalise();
|
|
|
|
op.Controle.Reiniciar();
|
|
op.DefinirTipoMovimentoControle(TipoMovimentoDirecional.RodasDianteiras);
|
|
op.ControleAnterior.Reiniciar();
|
|
|
|
op.GPSTrajetoria = new List<GPSModel>();
|
|
|
|
op.Trajetoria?.ProjetarTrajetoriaFixa();
|
|
op.Trajetoria.VerificacaoInicialMeioRuaConcluida = false;
|
|
RedisService.Publish(CmdKey.ManagerWorkerRx, JsonConvert.SerializeObject(new { cmd = ManagerWorkerCommandType.IniciarMPC }));
|
|
}
|
|
|
|
public void ReiniciarSimulacao()
|
|
{
|
|
if (!EhOperacaoAtual(nameof(ReiniciarSimulacao)))
|
|
return;
|
|
|
|
this.ReiniciarOperacao(false);
|
|
|
|
var Topico = Variaveis.MqttServiceLocal.Topicos.FirstOrDefault(x => x.Topico == MapasVariaveisModel.TopicoSelecaoRuasMapa);
|
|
Topico.Mensagens.Add(new MqttService.MqttTopicosMensagensModel()
|
|
{
|
|
Mensagem = "[]",
|
|
Momento = DateTime.Now
|
|
});
|
|
}
|
|
|
|
public void IniciarTreinamento()
|
|
{
|
|
if (!EhOperacaoAtual(nameof(IniciarTreinamento)))
|
|
return;
|
|
|
|
var op = this;
|
|
var dispSen = op.DispSen;
|
|
var dispAtu = op.DispAtu;
|
|
var dispMvd = op.DispMvd;
|
|
|
|
op.Treinando = true;
|
|
|
|
op.Sensoriamento.Operacao.OperacaoIniciada = true;
|
|
op.Sensoriamento.Operacao.DataInicio = DateTime.Now;
|
|
op.Sensoriamento.Operacao.DataFim = DateTime.MinValue;
|
|
|
|
op.ID = "";
|
|
|
|
dispMvd?.Dados?.ReiniciarLeituras(dispMvd.Dados);
|
|
dispAtu?.Dados?.ReiniciarLeituras(dispAtu.Dados);
|
|
dispSen?.Dados?.ReiniciarLeituras(dispSen.Dados);
|
|
|
|
op.Controle.Angulo = 0;
|
|
op.Controle.PercentualVelocidadeSP = 0;
|
|
|
|
op.GPSTrajetoria = new List<GPSModel>();
|
|
}
|
|
|
|
public static string DeserializarDadosOperacao(string caminho, string arquivo)
|
|
{
|
|
string pastaBase = Path.GetDirectoryName(caminho) ?? "";
|
|
|
|
// compatibilidade com o modelo antigo:
|
|
// data.lgop -> {arquivo}.json
|
|
string caminhoJsonAntigo = Path.Combine(pastaBase, arquivo + ".json");
|
|
if (File.Exists(caminhoJsonAntigo))
|
|
{
|
|
string opStr = File.ReadAllText(caminhoJsonAntigo);
|
|
if (!string.IsNullOrWhiteSpace(opStr) && !opStr.TrimEnd().EndsWith("]"))
|
|
opStr += "]";
|
|
|
|
return string.IsNullOrWhiteSpace(opStr) ? "[]" : opStr;
|
|
}
|
|
|
|
// novo modelo:
|
|
// {arquivo}_{idx}_{datahora}.jsonl
|
|
string[] arquivosJsonl = Directory.Exists(pastaBase)
|
|
? Directory.GetFiles(pastaBase, $"{arquivo}_*.jsonl")
|
|
.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)
|
|
.ToArray()
|
|
: Array.Empty<string>();
|
|
|
|
if (arquivosJsonl.Length == 0)
|
|
return "[]";
|
|
|
|
var sb = new StringBuilder();
|
|
sb.Append("[");
|
|
|
|
bool primeiro = true;
|
|
|
|
foreach (string arq in arquivosJsonl)
|
|
{
|
|
foreach (string linha in File.ReadLines(arq))
|
|
{
|
|
string json = linha?.Trim();
|
|
|
|
if (string.IsNullOrWhiteSpace(json))
|
|
continue;
|
|
|
|
if (!primeiro)
|
|
sb.Append(",");
|
|
|
|
sb.Append(json);
|
|
primeiro = false;
|
|
}
|
|
}
|
|
|
|
sb.Append("]");
|
|
return sb.ToString();
|
|
}
|
|
|
|
private void SalvarOperacao()
|
|
{
|
|
var op = this;
|
|
|
|
if (string.IsNullOrWhiteSpace(op.ID))
|
|
return;
|
|
|
|
string pastaOperacao = Path.Combine(Variaveis.CaminhoOperacoes, op.ID);
|
|
Directory.CreateDirectory(pastaOperacao);
|
|
|
|
string caminhoOperacao = Path.Combine(pastaOperacao, "operacao.opr");
|
|
|
|
try
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(op.OprPath) && File.Exists(op.OprPath))
|
|
{
|
|
File.Copy(op.OprPath, caminhoOperacao, overwrite: true);
|
|
return;
|
|
}
|
|
|
|
// Operação recebida da base: salva os parâmetros como .opr
|
|
string json = JsonConvert.SerializeObject(op.Parametros, Formatting.Indented);
|
|
File.WriteAllText(caminhoOperacao, json, Encoding.UTF8);
|
|
|
|
Variaveis.MostrarLog($"[OperacaoModel.SalvarOperacao] Operação salva a partir dos parâmetros. OprPath='{op.OprPath}'");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel.SalvarOperacao] Erro ao salvar operação: " + ex);
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region CALIBRAGEM
|
|
|
|
public async Task RealizarCalibragemInicialAsync(bool forcar)
|
|
{
|
|
var op = this;
|
|
|
|
if (!ReferenceEquals(Variaveis.OperacaoEmAndamento, this))
|
|
return;
|
|
|
|
if (!await _calibragemGate.WaitAsync(0))
|
|
return;
|
|
|
|
TipoMovimentoDirecional tipoControle = op.Controle.TipoMovimento;
|
|
bool entrouEmCalibragem = false;
|
|
|
|
try
|
|
{
|
|
GarantirEstruturaModsCalibragem(op);
|
|
|
|
var modsCalibragem = op.Sensoriamento.Operacao.ModsCalibragem;
|
|
|
|
bool modsCalibrados =
|
|
modsCalibragem.Any() &&
|
|
modsCalibragem.All(x =>
|
|
x.Value != null &&
|
|
x.Value.Values.Count > 0 &&
|
|
x.Value.Values.All(y => y)
|
|
);
|
|
|
|
if (!forcar && modsCalibrados)
|
|
{
|
|
//op.Sensoriamento.InserirLog(T_Code.Mod, StatusModulo.Operante, 100, "Todos os módulos já foram calibrados anteriormente, não irá calibrar novamente.");
|
|
return;
|
|
}
|
|
|
|
var dispAtu = op.DispAtu;
|
|
var dispMvd = op.DispMvd;
|
|
|
|
var statusValidos = new List<StatusModulo>()
|
|
{
|
|
StatusModulo.Operante,
|
|
StatusModulo.Alerta
|
|
};
|
|
|
|
var saude = op.Sensoriamento?.OperadorSaude?.ModulosSaude ?? new List<ManagerWorkerMessageResponseModulosPendentesModel>();
|
|
var pControle = op.Parametros?.Controle;
|
|
|
|
if (pControle == null)
|
|
return;
|
|
|
|
bool atuSaudavel = statusValidos.Contains(saude.FirstOrDefault(x => x.modulo == T_Code.Atu)?.status ?? StatusModulo.Desconectado);
|
|
bool dirSaudavel = statusValidos.Contains(saude.FirstOrDefault(x => x.modulo == T_Code.Dir)?.status ?? StatusModulo.Desconectado);
|
|
bool movSaudavel = statusValidos.Contains(saude.FirstOrDefault(x => x.modulo == T_Code.Mov)?.status ?? StatusModulo.Desconectado);
|
|
|
|
bool reservatorioOk = (op.Sensoriamento?.Atuador?.PercentualReservatorio ?? 0) > VariaveisEquipamento.PercentualReservatorioMinCritio;
|
|
|
|
bool bombaOk = dispAtu?.Dados?.BombaPressurizadora?.Inicializado ?? false;
|
|
|
|
bool calibragemAtuNecessaria =
|
|
pControle.PulverizadorAutomatico &&
|
|
bombaOk &&
|
|
reservatorioOk &&
|
|
dispAtu?.Dados != null &&
|
|
atuSaudavel &&
|
|
DeveCalibrar(modsCalibragem, T_Code.Atu, forcar);
|
|
|
|
bool calibragemDirNecessaria =
|
|
dispMvd?.Dados != null &&
|
|
dirSaudavel &&
|
|
DeveCalibrar(modsCalibragem, T_Code.Dir, forcar);
|
|
|
|
bool calibragemMovNecessaria =
|
|
dispMvd?.Dados != null &&
|
|
movSaudavel &&
|
|
DeveCalibrar(modsCalibragem, T_Code.Mov, forcar);
|
|
|
|
if (!calibragemAtuNecessaria && !calibragemDirNecessaria && !calibragemMovNecessaria)
|
|
{
|
|
if (forcar)
|
|
{
|
|
string motivo =
|
|
$"Calibragem não necessária. " +
|
|
$"AtuNec={calibragemAtuNecessaria}, DirNec={calibragemDirNecessaria}, MovNec={calibragemMovNecessaria}, " +
|
|
$"PulvAuto={pControle.PulverizadorAutomatico}, BombaOk={bombaOk}, ReservatorioOk={reservatorioOk}, " +
|
|
$"AtuSaude={atuSaudavel}, DirSaude={dirSaudavel}, MovSaude={movSaudavel}";
|
|
|
|
Variaveis.MostrarLog("[OperacaoModel] [RealizarCalibragemInicialAsync] " + motivo);
|
|
|
|
op.Sensoriamento.InserirLog(T_Code.Mod, StatusModulo.Operante, 100, motivo);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
entrouEmCalibragem = true;
|
|
|
|
op.DefinirEstadoCalibragemRuntime(true, true);
|
|
|
|
Variaveis.MostrarLog("[OperacaoModel] [RealizarCalibragemInicialAsync] Pausa para calibragem inicial");
|
|
|
|
op.Sensoriamento.InserirLog(T_Code.Mod, StatusModulo.Operante, 100, "Pausa para calibragem inicial");
|
|
|
|
await Task.Delay(5000);
|
|
|
|
if (!ReferenceEquals(Variaveis.OperacaoEmAndamento, this))
|
|
return;
|
|
|
|
if (!op.Sensoriamento.Operacao.OperacaoIniciada)
|
|
return;
|
|
|
|
Variaveis.MostrarLog("[OperacaoModel] [RealizarCalibragemInicialAsync] Calibragem dos módulos iniciada...");
|
|
|
|
op.Sensoriamento.InserirLog(T_Code.Mod, StatusModulo.Operante, 100, "Calibragem dos módulos iniciada...");
|
|
|
|
var tasks = new List<Task>();
|
|
|
|
if (calibragemAtuNecessaria)
|
|
tasks.AddRange(dispAtu.Dados.RealizarCalibragemAsync(forcar));
|
|
|
|
if (calibragemDirNecessaria)
|
|
tasks.AddRange(dispMvd.Dados.RealizarCalibragemDirAsync(forcar));
|
|
|
|
if (calibragemMovNecessaria)
|
|
tasks.AddRange(dispMvd.Dados.RealizarCalibragemMovAsync(forcar));
|
|
|
|
if (tasks.Count == 0)
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel] [RealizarCalibragemInicialAsync] Nenhuma calibragem foi iniciada.");
|
|
|
|
op.Sensoriamento.InserirLog(T_Code.Mod, StatusModulo.Alerta, 50, "Nenhuma calibragem foi iniciada.");
|
|
|
|
return;
|
|
}
|
|
|
|
var allTasks = Task.WhenAll(tasks);
|
|
var timeoutTask = Task.Delay(2 * 60 * 1000);
|
|
|
|
var completed = await Task.WhenAny(allTasks, timeoutTask);
|
|
|
|
if (completed == allTasks)
|
|
{
|
|
await allTasks;
|
|
|
|
Variaveis.MostrarLog("[OperacaoModel] [RealizarCalibragemInicialAsync] Calibragem finalizada.");
|
|
|
|
op.Sensoriamento.InserirLog(T_Code.Mod, StatusModulo.Operante, 100, "Calibragem finalizada.");
|
|
}
|
|
else
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel] [RealizarCalibragemInicialAsync] Timeout na calibragem. Liberando operação mesmo assim.");
|
|
|
|
op.Sensoriamento.InserirLog(T_Code.Mod, StatusModulo.Alerta, 50, "Timeout na calibragem. Liberando operação mesmo assim.");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Variaveis.MostrarLog($"[OperacaoModel] [RealizarCalibragemInicialAsync] Erro durante calibragem: {ex}");
|
|
|
|
op.Sensoriamento.InserirLog(T_Code.Mod, StatusModulo.Falha, 0, $"Erro durante calibragem: {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
op.DefinirTipoMovimentoControle(tipoControle);
|
|
|
|
if (entrouEmCalibragem)
|
|
{
|
|
op.DefinirEstadoCalibragemRuntime(false, false);
|
|
}
|
|
|
|
_calibragemGate.Release();
|
|
}
|
|
}
|
|
|
|
private static void GarantirEstruturaModsCalibragem(OperacaoModel op)
|
|
{
|
|
if (op.Sensoriamento.Operacao.ModsCalibragem == null)
|
|
op.Sensoriamento.Operacao.ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>();
|
|
|
|
var mods = op.Sensoriamento.Operacao.ModsCalibragem;
|
|
|
|
if (!mods.ContainsKey(T_Code.Mov) || mods[T_Code.Mov] == null)
|
|
mods[T_Code.Mov] = new Dictionary<string, bool>();
|
|
|
|
if (!mods.ContainsKey(T_Code.Dir) || mods[T_Code.Dir] == null)
|
|
mods[T_Code.Dir] = new Dictionary<string, bool>();
|
|
|
|
if (!mods.ContainsKey(T_Code.Atu) || mods[T_Code.Atu] == null)
|
|
mods[T_Code.Atu] = new Dictionary<string, bool>();
|
|
}
|
|
|
|
private static bool DeveCalibrar(Dictionary<T_Code, Dictionary<string, bool>> modsCalibragem, T_Code modulo, bool forcar)
|
|
{
|
|
if (!modsCalibragem.ContainsKey(modulo) || modsCalibragem[modulo] == null)
|
|
return true;
|
|
|
|
var mods = modsCalibragem[modulo];
|
|
|
|
if (!mods.Any())
|
|
return true;
|
|
|
|
if (forcar)
|
|
return true;
|
|
|
|
return mods.Any(x => !x.Value);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CONTROLE DA OPERACAO
|
|
|
|
public void DefinirTipoMovimentoControle(TipoMovimentoDirecional value)
|
|
{
|
|
if (!EhOperacaoAtual(nameof(DefinirTipoMovimentoControle)))
|
|
return;
|
|
|
|
var dispMvd = DispMvd;
|
|
|
|
if (dispMvd?.Dados?.Modulos != null && value != Controle.TipoMovimento)
|
|
{
|
|
switch (value)
|
|
{
|
|
case TipoMovimentoDirecional.RodasDianteiras:
|
|
dispMvd.Dados.Modulos.ForEach(x =>
|
|
{
|
|
x.MovMotor.Comandar = true;
|
|
x.DirMotor.Comandar = x.Modulo_ID.Contains("F");
|
|
x.DirMotor.Angulo_SP = x.DirMotor.Comandar ? Controle.Angulo : 0;
|
|
});
|
|
break;
|
|
|
|
case TipoMovimentoDirecional.RodasTraseiras:
|
|
dispMvd.Dados.Modulos.ForEach(x =>
|
|
{
|
|
x.MovMotor.Comandar = true;
|
|
x.DirMotor.Comandar = x.Modulo_ID.Contains("T");
|
|
x.DirMotor.Angulo_SP = x.DirMotor.Comandar ? Controle.Angulo : 0;
|
|
});
|
|
break;
|
|
|
|
default:
|
|
dispMvd.Dados.Modulos.ForEach(x =>
|
|
{
|
|
x.MovMotor.Comandar = true;
|
|
x.DirMotor.Comandar = true;
|
|
x.DirMotor.Angulo_SP = Controle.Angulo;
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
Controle.TipoMovimento = value;
|
|
}
|
|
|
|
public void AtualizaInformacoesControleOperacao()
|
|
{
|
|
if (!EhOperacaoAtual(nameof(AtualizaInformacoesControleOperacao)))
|
|
return;
|
|
|
|
var op = this;
|
|
|
|
var pControle = op.Parametros.Controle;
|
|
if (pControle.MovimentoAutomatico)
|
|
{
|
|
op.AtualizarDadosControle(false, new List<T_Code>() { T_Code.Mov });
|
|
}
|
|
if (pControle.DirecionalAutomatico)
|
|
{
|
|
op.AtualizarDadosControle(false, new List<T_Code>() { T_Code.Dir });
|
|
}
|
|
if (pControle.PulverizadorAutomatico)
|
|
{
|
|
op.AtualizarDadosControle(false, new List<T_Code>() { T_Code.Atu });
|
|
}
|
|
}
|
|
|
|
public void AtualizarDadosControle(bool ForcarEnvio, List<T_Code> Dispositivos)
|
|
{
|
|
if (!EhOperacaoAtual(nameof(AtualizarDadosControle)))
|
|
return;
|
|
|
|
var op = this;
|
|
|
|
DateTime Agora = DateTime.Now;
|
|
|
|
var pControle = op.Parametros.Controle;
|
|
var _Controle = op.Controle;
|
|
var mm = op.Parametros.ModulosMandatorios;
|
|
|
|
foreach (var Ctrl in _Controle.TiposControle.Where(x => Dispositivos.Contains(x.Tipo)))
|
|
{
|
|
if (!ForcarEnvio && false)
|
|
{
|
|
if (mm.Any(x => x.Dispositivo == Ctrl.Tipo && !x.Utilizar))
|
|
continue;
|
|
if (Ctrl.Tipo == T_Code.Atu && !pControle.PulverizadorAutomatico)
|
|
continue;
|
|
if (Ctrl.Tipo == T_Code.Mov && !pControle.MovimentoAutomatico)
|
|
continue;
|
|
if (Ctrl.Tipo == T_Code.Dir && !pControle.DirecionalAutomatico)
|
|
continue;
|
|
}
|
|
|
|
if (ForcarEnvio || ((Agora - Ctrl.UltimoComando).TotalMilliseconds > Ctrl.DelayEnvioComando))
|
|
{
|
|
var Protocolos = EnviarProtocoloComando(Ctrl.Tipo, ForcarEnvio);
|
|
Ctrl.UltimoComando = Agora;
|
|
Ctrl.DelayEnvioComando = Ctrl.DelayEnvioComandoBase + Ctrl.DelayEnvioComandoExtra;
|
|
Ctrl.DelayEnvioComandoExtra = 0;
|
|
Ctrl.Comandos.AddRange(Protocolos);
|
|
}
|
|
}
|
|
}
|
|
|
|
public List<string> EnviarProtocoloComando(T_Code Tipo, bool ForcarEnvio)
|
|
{
|
|
if (!EhOperacaoAtual(nameof(EnviarProtocoloComando)))
|
|
return new List<string>();
|
|
|
|
var op = this;
|
|
|
|
if (!op.Sensoriamento.Operacao.OperacaoIniciada && !ForcarEnvio)
|
|
return new List<string>();
|
|
|
|
List<string> Protocolos = new List<string>();
|
|
|
|
var pControle = op.Parametros.Controle;
|
|
var _Controle = op.Controle;
|
|
var _ControleAnterior = op.ControleAnterior;
|
|
var DirecaoAtual = _Controle.TiposControle.FirstOrDefault(x => x.Tipo == Tipo).DirecaoAtual;
|
|
|
|
switch (Tipo)
|
|
{
|
|
case T_Code.Mov:
|
|
{
|
|
var modsAtualizar = op.DispMvd.Dados.Modulos.Where(Mod => Mod.MovMotor.NovoRPMNecessario).Select(x => x.Modulo_ID).ToList();
|
|
bool envioNecessario = ForcarEnvio || _Controle.RPM_SP != _ControleAnterior.RPM_SP || _Controle.EmFreio != _ControleAnterior.EmFreio;
|
|
if (envioNecessario || modsAtualizar.Any())
|
|
{
|
|
foreach (var Mod in op.DispMvd.Dados.Modulos.Where(x => envioNecessario ? true : modsAtualizar.Contains(x.Modulo_ID)))
|
|
{
|
|
Mod.MovMotor.EnviarComandoControle(DirecaoAtual);
|
|
}
|
|
}
|
|
|
|
//Variaveis.MostrarLog($"Velocidade SP alterada de {_ControleAnterior.PercentualVelocidadeSP} para {_Controle.PercentualVelocidadeSP}");
|
|
|
|
_ControleAnterior.PercentualVelocidadeSP = _Controle.PercentualVelocidadeSP;
|
|
_ControleAnterior.EmFreio = _Controle.EmFreio;
|
|
|
|
RedisService.AtualizarCampos(
|
|
CtxKey.DadosControle,
|
|
("velocidade_sp_ant", _Controle.PercentualVelocidadeSP),
|
|
("em_freio_ant", _Controle.EmFreio)
|
|
);
|
|
|
|
Protocolos = new List<string>()
|
|
{
|
|
DirecaoAtual.ToString() + ";" + _Controle.RPM_SP.ToString() + ";" + (ForcarEnvio ? "1": "0")
|
|
};
|
|
break;
|
|
}
|
|
case T_Code.Dir:
|
|
{
|
|
bool envioNecessario = ForcarEnvio || _Controle.Angulo != _ControleAnterior.Angulo || _Controle.TipoMovimento != _ControleAnterior.TipoMovimento;
|
|
var modsAtualizar = op.DispMvd.Dados.Modulos.Where(Mod => !Mod.DirMotor.AtingiuAnguloSP).Select(x => x.Modulo_ID).ToList();
|
|
if (!MKS057DCanService.Referenciando && (envioNecessario || modsAtualizar.Any()))
|
|
{
|
|
foreach (var Mod in op.DispMvd.Dados.Modulos.Where(x => envioNecessario ? true : modsAtualizar.Contains(x.Modulo_ID)))
|
|
{
|
|
Mod.DirMotor.EnviarComandoControle(DirecaoAtual);
|
|
}
|
|
}
|
|
|
|
//Variaveis.MostrarLog($"Angulo SP alterado de {_ControleAnterior.Angulo:F2} para {_Controle.Angulo:F2}");
|
|
|
|
_ControleAnterior.Angulo = _Controle.Angulo;
|
|
_ControleAnterior.TipoMovimento = _Controle.TipoMovimento;
|
|
|
|
RedisService.AtualizarCampos(
|
|
CtxKey.DadosControle,
|
|
("angulo_sp_ant", _Controle.Angulo),
|
|
("tipo_movimento_direcional_ant", _Controle.TipoMovimento)
|
|
);
|
|
|
|
Protocolos = new List<string>()
|
|
{
|
|
DirecaoAtual.ToString() + ";" + _Controle.Angulo.ToString() + ";" + _Controle.TipoMovimento.ToString() + ";" + (ForcarEnvio ? "1": "0")
|
|
};
|
|
break;
|
|
}
|
|
case T_Code.Atu:
|
|
{
|
|
op.DispAtu?.Dados?.SincronizarBombaPressurizadoraAutomatica();
|
|
var bicos = op.DispAtu?.Dados?.BicosPulverizadores ?? new List<AtuadorBicoModel>();
|
|
|
|
for (int i = 0; i < bicos.Count; i++)
|
|
{
|
|
Estado comandoEstado = bicos[i].ComandoAtuar ? Estado.Ligado : Estado.Desligado;
|
|
if (ForcarEnvio || comandoEstado != bicos[i]._EstadoLeitura)
|
|
{
|
|
op.DispAtu?.Dados?.EnviarComandoFisicoBico(
|
|
bicos[i],
|
|
CanMessagePosicaoDados.Command1,
|
|
setarControle: true,
|
|
status: bicos[i].ComandoAtuar
|
|
);
|
|
}
|
|
}
|
|
|
|
Protocolos = new List<string>()
|
|
{
|
|
string.Join(";", bicos.Select(x => x.ComandoAtuar ? "1" : "0")) + ";" + (ForcarEnvio ? "1": "0")
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
|
|
_Controle.TiposControle.FirstOrDefault(x => x.Tipo == Tipo).UltimaDirecao = DirecaoAtual;
|
|
|
|
return Protocolos;
|
|
}
|
|
|
|
|
|
private async Task tmrLeituras_Tick()
|
|
{
|
|
if (!Variaveis.IsAgroBase)
|
|
return;
|
|
|
|
if (!ReferenceEquals(Variaveis.OperacaoEmAndamento, this))
|
|
{
|
|
Variaveis.MostrarLog(
|
|
$"[OperacaoModel.{nameof(tmrLeituras_Tick)}] Timer órfão ignorado. " +
|
|
$"TimerHash={GetHashCode()}, AtualHash={Variaveis.OperacaoEmAndamento?.GetHashCode()}"
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
var op = this;
|
|
|
|
op.AtualizarSensoriamentoSeguro();
|
|
//Variaveis.LoraService?.EnviarDadosParaBase();
|
|
|
|
if (op.Parametros?.Modo == ModoOperacao.Manual)
|
|
{
|
|
var Sonar = op.Sensoriamento?.OperadorVisual;
|
|
Sonar?.Resumo?.AtualizarStatusBloqueioManual(Sonar, true);
|
|
if (Sonar?.Resumo?.EnviarComandoParada ?? false)
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel] Deve enviar o comando de parada em tmrLeituras_Tick");
|
|
//GeneralJoystick.EnviaComandoMotor(Keys.Escape, Disp: T_Code.Mov, ForcarComando: true);
|
|
GeneralJoystick.ProcessarDadosControle(BotoesJoystick.Xis, true, ForcarComando: true);
|
|
if (op.Parametros?.Controle?.FrenagemAutomaticaAoParar ?? false)
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel] Deve enviar o comando de freio em tmrLeituras_Tick");
|
|
GeneralJoystick.ProcessarDadosControle(BotoesJoystick.Bolinha, false, ForcarComando: true);
|
|
}
|
|
}
|
|
|
|
if (!op.Sensoriamento.Operacao.OperacaoLiberada)
|
|
{
|
|
var _Controle = op.Controle;
|
|
if (_Controle.TiposControle?.FirstOrDefault(x => x?.Tipo == T_Code.Mov)?.DirecaoAtual != Direcao.Parado)
|
|
{
|
|
//GeneralJoystick.EnviaComandoMotor(Keys.Escape, Disp: T_Code.Mov, ForcarComando: true);
|
|
GeneralJoystick.ProcessarDadosControle(BotoesJoystick.Xis, true, ForcarComando: true);
|
|
}
|
|
if (_Controle.TiposControle?.FirstOrDefault(x => x?.Tipo == T_Code.Dir)?.UltimaDirecao != Direcao.Parado)
|
|
{
|
|
//GeneralJoystick.EnviaComandoMotor(Keys.Escape, Disp: T_Code.Dir, ForcarComando: true);
|
|
GeneralJoystick.ProcessarDadosControle(BotoesJoystick.SEsquerda, true, ForcarComando: true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task tmrComunicacao_Tick()
|
|
{
|
|
if (!Variaveis.IsAgroBase)
|
|
return;
|
|
|
|
if (!ReferenceEquals(Variaveis.OperacaoEmAndamento, this))
|
|
{
|
|
Variaveis.MostrarLog(
|
|
$"[OperacaoModel.{nameof(tmrComunicacao_Tick)}] Timer órfão ignorado. " +
|
|
$"TimerHash={GetHashCode()}, AtualHash={Variaveis.OperacaoEmAndamento?.GetHashCode()}"
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
var service = Variaveis.MqttServiceBase;
|
|
|
|
if (service == null)
|
|
return;
|
|
|
|
bool baseEncontrada = (DateTime.Now - VariaveisOperacao.PosicaoBase.UltimoComandoRespondido).TotalSeconds < 10;
|
|
|
|
MqttService.MqttTopicosModel topico = null;
|
|
|
|
if (!baseEncontrada)
|
|
{
|
|
topico = service.Topicos.FirstOrDefault(x => x.Topico == VariaveisMonitoramento.TopicoMqttDispositivos);
|
|
|
|
if (topico == null)
|
|
return;
|
|
|
|
var discovery = new
|
|
{
|
|
rover_id = VariaveisEquipamento.Parametros.serial_number,
|
|
rover_ip = VariaveisEquipamento.Parametros.rover_ip,
|
|
session_id = _discoverySessionId,
|
|
sent_at_utc = DateTime.UtcNow
|
|
};
|
|
|
|
string msg = JsonConvert.SerializeObject(discovery);
|
|
|
|
await service.PublishWithResultAsync(topico, msg);
|
|
|
|
return;
|
|
}
|
|
|
|
topico = service.Topicos.FirstOrDefault(x => x.Topico == VariaveisEquipamento.TopicoMqttTelemetria.Replace("<id>", VariaveisEquipamento.Parametros.serial_number));
|
|
|
|
if (topico == null)
|
|
return;
|
|
|
|
var op = this;
|
|
var dados = op.Parametros.DadosLeitura;
|
|
|
|
if (dados == null)
|
|
return;
|
|
|
|
dados.Atualizar();
|
|
|
|
OperacaoParametrosDadosModel snapshot = dados.Clone();
|
|
|
|
long sequence = Interlocked.Increment(
|
|
ref _telemetrySequence
|
|
);
|
|
|
|
/*
|
|
* Por enquanto mantemos o payload como OperacaoParametrosDadosModel
|
|
* puro para compatibilidade com a base. O sequence já fica calculado
|
|
* aqui para a próxima etapa, quando entrarmos no TelemetryEnvelope.
|
|
*/
|
|
|
|
string payload = JsonConvert.SerializeObject(snapshot);
|
|
|
|
MqttPublishResult result = await service.PublishWithResultAsync(topico, payload);
|
|
|
|
if (result.Succeeded)
|
|
{
|
|
/*
|
|
* O cursor dos logs só avança se a telemetria foi aceita
|
|
* pelo broker. Assim, se o publish falhar, os logs entram
|
|
* novamente no próximo snapshot.
|
|
*/
|
|
dados.UltimoEnvioLog = snapshot.Momento;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ============================================================================
|
|
// CAMPOS
|
|
// ============================================================================
|
|
|
|
private static readonly SemaphoreSlim _baseCommandGate = new SemaphoreSlim(1, 1);
|
|
private static readonly object _baseCommandDedupeLock = new object();
|
|
private static readonly Dictionary<string, DateTime> _baseCommandDedupe = new Dictionary<string, DateTime>();
|
|
private static readonly TimeSpan BaseCommandDedupeWindow = TimeSpan.FromMilliseconds(1500);
|
|
|
|
|
|
// ============================================================================
|
|
// PUBLICAÇÃO DE PARÂMETROS
|
|
// ============================================================================
|
|
|
|
private void EnviarParametorsOperacao()
|
|
{
|
|
Forget(
|
|
this.EnviarParametrosOperacaoAsync(),
|
|
"Enviar parâmetros da operação"
|
|
);
|
|
}
|
|
|
|
private async Task EnviarParametrosOperacaoAsync()
|
|
{
|
|
var service = Variaveis.MqttServiceBase;
|
|
|
|
if (service == null)
|
|
return;
|
|
|
|
string topicName = VariaveisEquipamento.TopicoMqttParametros.Replace("<id>", VariaveisEquipamento.Parametros.serial_number);
|
|
|
|
var topico = service.Topicos.FirstOrDefault(x => x.Topico == topicName);
|
|
|
|
if (topico == null)
|
|
return;
|
|
|
|
var op = this;
|
|
|
|
var parametros = op?.Parametros;
|
|
|
|
if (parametros == null)
|
|
return;
|
|
|
|
string msg = JsonConvert.SerializeObject(parametros);
|
|
|
|
/*
|
|
* Preferencial com o MqttService novo.
|
|
* Se sua versão ainda não tiver PublishWithResultAsync,
|
|
* troque este bloco por:
|
|
*
|
|
* await service.PublishAsync(topico, msg);
|
|
*/
|
|
MqttPublishResult result = await service.PublishWithResultAsync(topico, msg).ConfigureAwait(false);
|
|
|
|
if (!result.Succeeded)
|
|
{
|
|
Variaveis.MostrarLog("[ComandoBase] Falha ao publicar parâmetros: " + result.Status + " " + result.Error);
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================================
|
|
// ENTRADA COMPATÍVEL
|
|
// ============================================================================
|
|
|
|
public void ExecutaComandoDaBase(OperacaoComandoBaseModel controleBase)
|
|
{
|
|
Forget(
|
|
this.ExecutaComandoDaBaseAsync(controleBase),
|
|
"Executar comando da base"
|
|
);
|
|
}
|
|
|
|
public async Task ExecutaComandoDaBaseAsync(OperacaoComandoBaseModel controleBase)
|
|
{
|
|
if (controleBase == null)
|
|
return;
|
|
|
|
if (Variaveis.Fechando)
|
|
return;
|
|
|
|
var opAtual = Variaveis.OperacaoEmAndamento;
|
|
|
|
if (opAtual == null)
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel.ExecutaComandoDaBaseAsync] Ignorado: não existe OperacaoEmAndamento.");
|
|
return;
|
|
}
|
|
|
|
if (!ReferenceEquals(this, opAtual))
|
|
{
|
|
Variaveis.MostrarLog(
|
|
$"[OperacaoModel.ExecutaComandoDaBaseAsync] Comando recebido por instância antiga. " +
|
|
$"ReceiverHash={GetHashCode()}, AtualHash={opAtual.GetHashCode()}, " +
|
|
$"Cmd={controleBase.Dispositivo}/{controleBase.Tecla}. Redirecionando."
|
|
);
|
|
|
|
await opAtual.ExecutaComandoDaBaseAsync(controleBase).ConfigureAwait(false);
|
|
return;
|
|
}
|
|
|
|
var op = opAtual;
|
|
|
|
if (op.EhComandoDuplicado(controleBase))
|
|
return;
|
|
|
|
bool entered = false;
|
|
|
|
try
|
|
{
|
|
await _baseCommandGate.WaitAsync().ConfigureAwait(false);
|
|
entered = true;
|
|
|
|
await op.ExecutaComandoDaBaseInternoAsync(controleBase).ConfigureAwait(false);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel.ExecutaComandoDaBaseAsync] Erro ao executar comando: " + ex);
|
|
}
|
|
finally
|
|
{
|
|
if (entered)
|
|
_baseCommandGate.Release();
|
|
}
|
|
}
|
|
|
|
private async Task ExecutaComandoDaBaseInternoAsync(OperacaoComandoBaseModel controleBase)
|
|
{
|
|
var op = this;
|
|
|
|
if (op == null)
|
|
return;
|
|
|
|
switch (controleBase.Dispositivo)
|
|
{
|
|
case T_Code.Mod:
|
|
await op.ExecutarComandoModuloAsync(controleBase, op).ConfigureAwait(false);
|
|
return;
|
|
|
|
case T_Code.Ipb:
|
|
op.ExecutarComandoIpBridge(controleBase);
|
|
return;
|
|
|
|
case T_Code.Gps:
|
|
op.ExecutarComandoGps(controleBase);
|
|
return;
|
|
|
|
case T_Code.Snr:
|
|
op.ExecutarComandoCameraCaminho(controleBase);
|
|
return;
|
|
|
|
case T_Code.Cam:
|
|
op.ExecutarComandoCameraSolo(controleBase);
|
|
return;
|
|
|
|
case T_Code.Atu:
|
|
op.ExecutarComandoAtuador(controleBase, op);
|
|
return;
|
|
|
|
case T_Code.Sen:
|
|
op.ExecutarComandoSensoriamento(controleBase, op);
|
|
return;
|
|
|
|
case T_Code.Dir:
|
|
if (controleBase.Tecla == BotoesJoystick.R3)
|
|
{
|
|
GeneralJoystick.ProcessarDadosControle(BotoesJoystick.R3, false, ID: controleBase._comp_id, ForcarComando: true);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case T_Code.Npc:
|
|
op.ExecutarComandoNpc(controleBase, op);
|
|
return;
|
|
|
|
case T_Code.Trj:
|
|
op.ExecutarComandoTrajetoria(controleBase, op);
|
|
return;
|
|
}
|
|
|
|
op.ExecutarComandoMovDirGenerico(controleBase, op);
|
|
}
|
|
|
|
|
|
// ============================================================================
|
|
// COMANDOS DE OPERAÇÃO
|
|
// ============================================================================
|
|
|
|
private async Task ExecutarComandoModuloAsync(OperacaoComandoBaseModel controleBase, OperacaoModel op)
|
|
{
|
|
op = Variaveis.OperacaoEmAndamento;
|
|
|
|
if (op == null)
|
|
return;
|
|
|
|
if (!ReferenceEquals(Variaveis.OperacaoEmAndamento, op))
|
|
return;
|
|
|
|
var parametros = controleBase.Parametros;
|
|
|
|
switch (controleBase.Tecla)
|
|
{
|
|
case BotoesJoystick.Share:
|
|
await op.EnviarParametrosOperacaoAsync().ConfigureAwait(false);
|
|
return;
|
|
|
|
case BotoesJoystick.Options:
|
|
if (parametros == null)
|
|
return;
|
|
|
|
if (Variaveis.OperacaoEmAndamento?.Sensoriamento?.Operacao?.OperacaoIniciada == true)
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel.ExecutarComandoModuloAsync] Ignorando carga completa de parâmetros com operação iniciada.");
|
|
return;
|
|
}
|
|
|
|
var novaOp = CarregarParamerosOperacaoBase(parametros);
|
|
|
|
if (novaOp != null)
|
|
await novaOp.EnviarParametrosOperacaoAsync().ConfigureAwait(false);
|
|
|
|
return;
|
|
|
|
case BotoesJoystick.Touchpad:
|
|
if (parametros == null)
|
|
return;
|
|
|
|
op.AtualizarParametrosParciais(parametros, op);
|
|
|
|
HealthWorkerService.AtualizarDadosOperacao(true);
|
|
|
|
await op.EnviarParametrosOperacaoAsync().ConfigureAwait(false);
|
|
return;
|
|
|
|
case BotoesJoystick.L1:
|
|
if (!op.Sensoriamento.Operacao.OperacaoIniciada)
|
|
await op.IniciarSimulacao().ConfigureAwait(false);
|
|
return;
|
|
|
|
case BotoesJoystick.L2:
|
|
if (!op.Sensoriamento.Operacao.OperacaoIniciada)
|
|
await op.IniciarOperacao().ConfigureAwait(false);
|
|
return;
|
|
|
|
case BotoesJoystick.L3:
|
|
if (op.Sensoriamento.Operacao.OperacaoIniciada)
|
|
await op.FinalizarOperacao().ConfigureAwait(false);
|
|
else
|
|
op.ReiniciarOperacao(true);
|
|
return;
|
|
|
|
case BotoesJoystick.R1:
|
|
op.ExecutarLiberacaoHumanaAutonomia(controleBase, op);
|
|
return;
|
|
}
|
|
}
|
|
|
|
private void AtualizarParametrosParciais(OperacaoParametrosModel parametros, OperacaoModel op)
|
|
{
|
|
if (op?.Parametros == null)
|
|
return;
|
|
|
|
if (parametros.Modo != null)
|
|
op.Parametros.Modo = parametros.Modo;
|
|
|
|
if (parametros.QtdBicos != null)
|
|
op.Parametros.QtdBicos = parametros.QtdBicos;
|
|
|
|
if (parametros.Descricao != null)
|
|
op.Parametros.Descricao = parametros.Descricao;
|
|
|
|
if (parametros.QtdCamerasSolo != null)
|
|
op.Parametros.QtdCamerasSolo = parametros.QtdCamerasSolo;
|
|
|
|
if (parametros.CapacidadeReservatorio != null)
|
|
op.Parametros.CapacidadeReservatorio = parametros.CapacidadeReservatorio;
|
|
|
|
if (parametros.Controle != null)
|
|
op.Parametros.Controle = parametros.Controle;
|
|
|
|
if (parametros.ParametrosMandatorios != null)
|
|
op.Parametros.ParametrosMandatorios = parametros.ParametrosMandatorios;
|
|
|
|
if (parametros.ModulosMandatorios != null)
|
|
{
|
|
op.Parametros.ModulosMandatorios = parametros.ModulosMandatorios;
|
|
op.DefinirComponentesEmUso();
|
|
}
|
|
}
|
|
|
|
private void ExecutarLiberacaoHumanaAutonomia(OperacaoComandoBaseModel controleBase, OperacaoModel op)
|
|
{
|
|
if (op?.Trajetoria?.AutonomiaCorredor?.Liberado ?? false)
|
|
return;
|
|
|
|
if (!TryDeserializeValue(controleBase._comp_value, out ValueTuple<int, bool, bool> data))
|
|
{
|
|
Variaveis.MostrarLog("[ComandoBase] Payload inválido para liberação humana.");
|
|
return;
|
|
}
|
|
|
|
op.Trajetoria?.AtualizarDadosAutonomiaCorredor(idxCorredor: data.Item1, bat_liberada: data.Item2, herb_liberado: data.Item3);
|
|
}
|
|
|
|
|
|
// ============================================================================
|
|
// COMANDOS INDIVIDUAIS
|
|
// ============================================================================
|
|
|
|
private void ExecutarComandoIpBridge(OperacaoComandoBaseModel controleBase)
|
|
{
|
|
bool ligar;
|
|
|
|
if (!TryDeserializeValue(controleBase._comp_value, out ligar))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ligar)
|
|
Variaveis.IniciarUDP();
|
|
else
|
|
Variaveis.StopUdpChannel();
|
|
}
|
|
|
|
private void ExecutarComandoGps(OperacaoComandoBaseModel controleBase)
|
|
{
|
|
if (!TryDeserializeValue(controleBase._comp_value, out ValueTuple<double?, double?> lever))
|
|
{
|
|
Variaveis.MostrarLog("[ComandoBase] Payload inválido para lever arm.");
|
|
return;
|
|
}
|
|
|
|
double? laLateral = lever.Item1;
|
|
double? laFrontal = lever.Item2;
|
|
|
|
if (laLateral == null && laFrontal == null)
|
|
return;
|
|
|
|
GPSService.LeverArm = new GeoLeverArm(
|
|
offsetFisicoFrontalCm: VariaveisEquipamento.LeverArmFrontalCm,
|
|
offsetFisicoLateralCm: VariaveisEquipamento.LeverArmLateralCm,
|
|
offsetCampoFrontalCm: laFrontal ?? 0,
|
|
offsetCampoLateralCm: laLateral ?? 0
|
|
);
|
|
}
|
|
|
|
private void ExecutarComandoCameraCaminho(OperacaoComandoBaseModel controleBase)
|
|
{
|
|
string cameraId = VariaveisEquipamento.Parametros.camera_caminhho_id;
|
|
|
|
if (string.IsNullOrWhiteSpace(cameraId))
|
|
return;
|
|
|
|
if (!TryDeserializeValue(controleBase._comp_value, out TipoFrameCamera frameType))
|
|
{
|
|
return;
|
|
}
|
|
|
|
RedisService.AtualizarCampos(
|
|
RedisService.CamKey(cameraId),
|
|
("streaming", controleBase.Tecla == BotoesJoystick.L1),
|
|
("frame_type", frameType)
|
|
);
|
|
}
|
|
|
|
private void ExecutarComandoCameraSolo(OperacaoComandoBaseModel controleBase)
|
|
{
|
|
var cameras = VariaveisEquipamento.Parametros.camera_ervas_id;
|
|
|
|
string cameraId = null;
|
|
|
|
if (cameras != null)
|
|
{
|
|
foreach (var mxid in cameras)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(mxid))
|
|
{
|
|
cameraId = mxid;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(cameraId))
|
|
return;
|
|
|
|
if (!TryDeserializeValue(controleBase._comp_value, out TipoFrameCamera frameType))
|
|
{
|
|
return;
|
|
}
|
|
|
|
RedisService.AtualizarCampos(
|
|
RedisService.CamKey(cameraId),
|
|
("streaming", controleBase.Tecla == BotoesJoystick.L1),
|
|
("frame_type", frameType)
|
|
);
|
|
}
|
|
|
|
private void ExecutarComandoAtuador(OperacaoComandoBaseModel controleBase, OperacaoModel op)
|
|
{
|
|
if (controleBase.Controle == null)
|
|
return;
|
|
|
|
var dadosAtu = op?.DispAtu?.Dados;
|
|
|
|
if (dadosAtu == null)
|
|
return;
|
|
|
|
S_Code comp = ResolverComponenteAtuador(dadosAtu, controleBase._comp_id);
|
|
|
|
if (comp == S_Code.sVZO)
|
|
{
|
|
Variaveis.MostrarLog("[ComandoBase] Componente ATU não encontrado: " + controleBase._comp_id);
|
|
return;
|
|
}
|
|
|
|
switch (comp)
|
|
{
|
|
case S_Code.sMOD:
|
|
if (controleBase.Controle.Altura != null)
|
|
{
|
|
op.Controle.AlturaBarra = (double)controleBase.Controle.Altura;
|
|
}
|
|
|
|
dadosAtu?.EnviarComandoFisicoReset();
|
|
return;
|
|
|
|
case S_Code.sBIC:
|
|
var bico = dadosAtu.BicosPulverizadores?.FirstOrDefault(x => x.ID == controleBase._comp_id);
|
|
|
|
if (controleBase._comp_value != null)
|
|
{
|
|
int angulo;
|
|
|
|
if (TryDeserializeValue(controleBase._comp_value, out angulo))
|
|
{
|
|
if (bico != null)
|
|
bico.AnguloAbertura = angulo;
|
|
}
|
|
}
|
|
|
|
dadosAtu?.EnviarComandoFisicoBico(
|
|
bico,
|
|
CanMessagePosicaoDados.Command1,
|
|
setarControle: true,
|
|
status: controleBase.Controle.Estado == true,
|
|
angulo: controleBase.Controle.AnguloSP
|
|
);
|
|
return;
|
|
|
|
case S_Code.sBMB:
|
|
var bomba = dadosAtu.BombasPressurizadoras?.FirstOrDefault(x => x.ID == controleBase._comp_id);
|
|
|
|
switch (controleBase.Controle.Comando)
|
|
{
|
|
case CanMessagePosicaoDados.Command2:
|
|
ModoControleBomba modo;
|
|
|
|
if (TryDeserializeValue(controleBase._comp_value, out modo))
|
|
{
|
|
if (op.Parametros?.Controle != null)
|
|
{
|
|
op.Parametros.Controle.AtuModoControle = modo;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
dadosAtu?.EnviarComandoFisicoBomba(
|
|
bomba,
|
|
CanMessagePosicaoDados.Command1,
|
|
setarControle: true,
|
|
status: controleBase.Controle.Estado == true,
|
|
potencia: controleBase.Controle.Potencia,
|
|
pressao: controleBase.Controle.Pressao,
|
|
modo: op.Parametros.Controle.AtuModoControle
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
private void ExecutarComandoSensoriamento(OperacaoComandoBaseModel controleBase, OperacaoModel op)
|
|
{
|
|
var dadosSen = op?.DispSen?.Dados;
|
|
|
|
if (dadosSen == null)
|
|
return;
|
|
|
|
S_Code comp = ResolverComponenteSensoriamento(dadosSen, controleBase._comp_id);
|
|
|
|
if (comp == S_Code.sVZO)
|
|
{
|
|
Variaveis.MostrarLog("[ComandoBase] Componente SEN não encontrado: " + controleBase._comp_id);
|
|
return;
|
|
}
|
|
|
|
GeneralJoystick.EnviarComandoSensoriamento(comp, controleBase._comp_id, controleBase._comp_value);
|
|
}
|
|
|
|
private void ExecutarComandoNpc(OperacaoComandoBaseModel controleBase, OperacaoModel op)
|
|
{
|
|
if (!TryDeserializeValue(controleBase._comp_value, out ValueTuple<CoolerControlService.CoolerMode, Estado?, Estado?, double?, double?> data))
|
|
{
|
|
Variaveis.MostrarLog("[ComandoBase] Payload inválido para cooler.");
|
|
return;
|
|
}
|
|
|
|
op?.DispSen?.Dados?.CoolerControl?.AlterarControle(data.Item1, entrada: data.Item2, saida: data.Item3, tempOn: data.Item4, tempTurbo: data.Item5);
|
|
}
|
|
|
|
private void ExecutarComandoTrajetoria(OperacaoComandoBaseModel controleBase, OperacaoModel op)
|
|
{
|
|
if (!TryDeserializeValue(controleBase._comp_value, out ValueTuple<double?, double?, List<double[]>> data))
|
|
{
|
|
Variaveis.MostrarLog("[ComandoBase] Payload inválido para retorno base.");
|
|
return;
|
|
}
|
|
|
|
GPSModel posicaoBase = null;
|
|
|
|
if (data.Item1 != null && data.Item2 != null)
|
|
{
|
|
posicaoBase = new GPSModel
|
|
{
|
|
Latitude = data.Item1.Value,
|
|
Longitude = data.Item2.Value
|
|
};
|
|
}
|
|
|
|
List<GPSModel> pontosRetornoPos = null;
|
|
|
|
if (data.Item3 != null && data.Item3.Any())
|
|
{
|
|
pontosRetornoPos = data.Item3
|
|
.Where(x => x != null && x.Length >= 2)
|
|
.Select(x => new GPSModel
|
|
{
|
|
Latitude = x[0],
|
|
Longitude = x[1]
|
|
})
|
|
.ToList();
|
|
}
|
|
|
|
op?.Trajetoria?.IniciarRetornoBase(posicaoBase, pontosRetornoPos);
|
|
}
|
|
|
|
|
|
// ============================================================================
|
|
// MOV/DIR GENÉRICO
|
|
// ============================================================================
|
|
|
|
private void ExecutarComandoMovDirGenerico(OperacaoComandoBaseModel controleBase, OperacaoModel op)
|
|
{
|
|
op.Sensoriamento.Operacao.Emergencia = controleBase.Emergencia;
|
|
|
|
if (op.Sensoriamento.Operacao.Emergencia)
|
|
return;
|
|
|
|
op.Sensoriamento.Operacao.Pausa = controleBase.Pausa;
|
|
|
|
if (op.Sensoriamento.Operacao.Pausa)
|
|
return;
|
|
|
|
if (controleBase.Controle == null)
|
|
return;
|
|
|
|
var cmdRover = GeneralJoystick.DeParaComandos.FirstOrDefault(x => x.botaoJoy == controleBase.Tecla);
|
|
|
|
if (cmdRover == null)
|
|
return;
|
|
|
|
if (cmdRover.Dispositivo == T_Code.Mov && (op.Parametros?.Controle?.MovimentoAutomatico ?? false) && op.Sensoriamento.Operacao.OperacaoIniciada)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (cmdRover.Dispositivo == T_Code.Dir && (op.Parametros?.Controle?.DirecionalAutomatico ?? false) && op.Sensoriamento.Operacao.OperacaoIniciada)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var controle = op.Controle;
|
|
|
|
if (controle == null)
|
|
return;
|
|
|
|
if (controleBase.Controle.PercentualVelocidadeSP != null)
|
|
controle.PercentualVelocidadeSP = (double)controleBase .Controle.PercentualVelocidadeSP;
|
|
|
|
if (controleBase.Controle.AnguloSP != null)
|
|
controle.Angulo = (double)controleBase.Controle.AnguloSP;
|
|
|
|
if (controleBase.Controle.TipoMovimentoDirecional != null)
|
|
op.DefinirTipoMovimentoControle((TipoMovimentoDirecional)controleBase.Controle.TipoMovimentoDirecional);
|
|
|
|
if (controleBase.Controle.EmFreio != null)
|
|
controle.EmFreio = (bool)controleBase.Controle.EmFreio;
|
|
|
|
switch (cmdRover.Dispositivo)
|
|
{
|
|
case T_Code.Mov:
|
|
GeneralJoystick.ProcessarDadosControle(
|
|
cmdRover.botaoJoy,
|
|
controleBase.Solto,
|
|
valorDesejado: controle.PercentualVelocidadeSP,
|
|
ForcarComando: true
|
|
);
|
|
break;
|
|
|
|
case T_Code.Dir:
|
|
GeneralJoystick.ProcessarDadosControle(
|
|
cmdRover.botaoJoy,
|
|
controleBase.Solto,
|
|
valorDesejado: controle.Angulo,
|
|
ForcarComando: true
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================================
|
|
// RESOLUÇÃO DE COMPONENTES
|
|
// ============================================================================
|
|
|
|
private static S_Code ResolverComponenteAtuador(AtuadorModel dadosAtu, string id)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(id))
|
|
return S_Code.sMOD;
|
|
|
|
if (dadosAtu?.BicosPulverizadores != null)
|
|
{
|
|
foreach (var item in dadosAtu.BicosPulverizadores)
|
|
if (item.ID == id)
|
|
return S_Code.sBIC;
|
|
}
|
|
|
|
if (dadosAtu?.BombasPressurizadoras != null)
|
|
{
|
|
foreach (var item in dadosAtu.BombasPressurizadoras)
|
|
if (item.ID == id)
|
|
return S_Code.sBMB;
|
|
}
|
|
|
|
if (dadosAtu?.Sensores != null)
|
|
{
|
|
foreach (var item in dadosAtu.Sensores)
|
|
if (item.ID == id)
|
|
return item.Componente;
|
|
}
|
|
|
|
return S_Code.sVZO;
|
|
}
|
|
|
|
private static S_Code ResolverComponenteSensoriamento(SensoriamentoModel dadosSen, string id)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(id))
|
|
return S_Code.sMOD;
|
|
|
|
if (dadosSen?.Reles != null)
|
|
{
|
|
foreach (var item in dadosSen.Reles)
|
|
if (item.ID == id)
|
|
return S_Code.sRLE;
|
|
}
|
|
|
|
if (dadosSen?.Servos != null)
|
|
{
|
|
foreach (var item in dadosSen.Servos)
|
|
if (item.ID == id)
|
|
return S_Code.sSRV;
|
|
}
|
|
|
|
if (dadosSen?.Sinaleiros != null)
|
|
{
|
|
foreach (var item in dadosSen.Sinaleiros)
|
|
if (item.ID == id)
|
|
return S_Code.sLED;
|
|
}
|
|
|
|
if (dadosSen?.Sensores != null)
|
|
{
|
|
foreach (var item in dadosSen.Sensores)
|
|
if (item.ID == id)
|
|
return item.Componente;
|
|
}
|
|
|
|
return S_Code.sVZO;
|
|
}
|
|
|
|
|
|
// ============================================================================
|
|
// DEDUPE
|
|
// ============================================================================
|
|
|
|
private bool EhComandoDuplicado(OperacaoComandoBaseModel comando)
|
|
{
|
|
if (!DeveDeduplicar(comando))
|
|
return false;
|
|
|
|
string key = CriarChaveDedupe(comando);
|
|
|
|
if (string.IsNullOrWhiteSpace(key))
|
|
return false;
|
|
|
|
DateTime now = DateTime.UtcNow;
|
|
|
|
lock (_baseCommandDedupeLock)
|
|
{
|
|
/*
|
|
* Limpeza barata.
|
|
*/
|
|
var expirados = _baseCommandDedupe
|
|
.Where(x => now - x.Value > TimeSpan.FromSeconds(5))
|
|
.Select(x => x.Key)
|
|
.ToList();
|
|
|
|
foreach (string item in expirados)
|
|
_baseCommandDedupe.Remove(item);
|
|
|
|
DateTime last;
|
|
|
|
if (_baseCommandDedupe.TryGetValue(key, out last) && now - last < BaseCommandDedupeWindow)
|
|
{
|
|
Variaveis.MostrarLog("[ComandoBase] Comando duplicado ignorado: " + comando.Dispositivo + "/" + comando.Tecla);
|
|
return true;
|
|
}
|
|
|
|
_baseCommandDedupe[key] = now;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static bool DeveDeduplicar(OperacaoComandoBaseModel comando)
|
|
{
|
|
if (comando == null)
|
|
return false;
|
|
|
|
/*
|
|
* Não deduplicamos MOV/DIR genérico porque o controle manual
|
|
* pode repetir o mesmo valor para manter atuação/estado.
|
|
*
|
|
* Deduplicamos comandos de alto nível e configuração, que são
|
|
* perigosos se QoS1 entregar duplicado.
|
|
*/
|
|
switch (comando.Dispositivo)
|
|
{
|
|
case T_Code.Mod:
|
|
case T_Code.Ipb:
|
|
case T_Code.Gps:
|
|
case T_Code.Snr:
|
|
case T_Code.Cam:
|
|
case T_Code.Npc:
|
|
case T_Code.Trj:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static string CriarChaveDedupe(OperacaoComandoBaseModel comando)
|
|
{
|
|
try
|
|
{
|
|
return string.Join(
|
|
"|",
|
|
comando.Dispositivo,
|
|
comando.Tecla,
|
|
comando._comp_id ?? string.Empty,
|
|
comando.Solto,
|
|
comando.Emergencia,
|
|
comando.Pausa,
|
|
JsonConvert.SerializeObject(comando._comp_value),
|
|
JsonConvert.SerializeObject(comando.Parametros),
|
|
JsonConvert.SerializeObject(comando.Controle)
|
|
);
|
|
}
|
|
catch
|
|
{
|
|
return comando.Dispositivo + "|" +
|
|
comando.Tecla + "|" +
|
|
comando._comp_id;
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================================
|
|
// CONVERSÃO SEGURA DE PAYLOAD
|
|
// ============================================================================
|
|
|
|
private static bool TryDeserializeValue<T>(object value, out T result)
|
|
{
|
|
result = default(T);
|
|
|
|
try
|
|
{
|
|
if (value == null)
|
|
return false;
|
|
|
|
if (value is T typed)
|
|
{
|
|
result = typed;
|
|
return true;
|
|
}
|
|
|
|
JToken token = value as JToken;
|
|
|
|
if (token != null)
|
|
{
|
|
result = token.ToObject<T>();
|
|
return true;
|
|
}
|
|
|
|
string text = value as string;
|
|
|
|
if (!string.IsNullOrWhiteSpace(text))
|
|
{
|
|
result = JsonConvert.DeserializeObject<T>(text);
|
|
return true;
|
|
}
|
|
|
|
Type target = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
|
|
|
|
if (target.IsEnum)
|
|
{
|
|
object enumValue = Enum.ToObject(target, value);
|
|
|
|
result = (T)enumValue;
|
|
return true;
|
|
}
|
|
|
|
result = (T)Convert.ChangeType(value, target);
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
result = default(T);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================================
|
|
// TASK FIRE-AND-FORGET OBSERVADO
|
|
// ============================================================================
|
|
|
|
private static void Forget(Task task, string context)
|
|
{
|
|
if (task == null)
|
|
return;
|
|
|
|
_ = task.ContinueWith(
|
|
completed =>
|
|
{
|
|
Exception ex = completed.Exception?.GetBaseException();
|
|
|
|
if (ex != null)
|
|
{
|
|
try
|
|
{
|
|
Variaveis.MostrarLog("[ComandoBase] " + context + ": " + ex.Message);
|
|
}
|
|
catch { }
|
|
}
|
|
},
|
|
CancellationToken.None,
|
|
TaskContinuationOptions.OnlyOnFaulted |
|
|
TaskContinuationOptions.ExecuteSynchronously,
|
|
TaskScheduler.Default
|
|
);
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
#region REGISTRO DE LOGS
|
|
|
|
private async Task tmrLogs_Tick()
|
|
{
|
|
var op = this;
|
|
|
|
if (!ReferenceEquals(Variaveis.OperacaoEmAndamento, op))
|
|
{
|
|
Variaveis.MostrarLog($"[OperacaoModel.tmrLogs_Tick] Timer órfão parado. TimerHash={GetHashCode()}, OperacaoTimer={ID}, OperacaoAtual={Variaveis.OperacaoEmAndamento?.ID}");
|
|
_tmrLogsOperacao?.Dispose();
|
|
return;
|
|
}
|
|
|
|
if (op.Sensoriamento?.Operacao?.OperacaoIniciada != true)
|
|
return;
|
|
|
|
bool salvou = await op.SalvarLogsSeguroAsync(false);
|
|
|
|
if (!salvou)
|
|
return;
|
|
|
|
if (op.idxLog % 10 == 0)
|
|
{
|
|
AudioAlertaService.AlertaSonoroPorStatus(op.Sensoriamento.Operacao.StatusOperacaoAtual);
|
|
}
|
|
|
|
if (op.idxLog % 5 == 0 && !op.CalibrandoRuntime && op.PodeTentarCalibragemAutomatica())
|
|
{
|
|
op.RegistrarTentativaCalibragem();
|
|
_ = Task.Run(async () => await op.RealizarCalibragemInicialAsync(false));
|
|
}
|
|
}
|
|
|
|
private async Task<bool> SalvarLogsSeguroAsync(bool fim)
|
|
{
|
|
if (!await _salvarLogsGate.WaitAsync(0))
|
|
{
|
|
if (!fim)
|
|
{
|
|
Variaveis.MostrarLog($"[OperacaoModel.SalvarLogsSeguroAsync] Ignorado: já existe salvamento em execução. Operacao={ID}, idxLog={idxLog}");
|
|
return false;
|
|
}
|
|
|
|
await _salvarLogsGate.WaitAsync();
|
|
}
|
|
|
|
try
|
|
{
|
|
return SalvarLogs(fim);
|
|
}
|
|
finally
|
|
{
|
|
_salvarLogsGate.Release();
|
|
}
|
|
}
|
|
|
|
public bool SalvarLogs(bool Fim)
|
|
{
|
|
var op = this;
|
|
|
|
if (op == null)
|
|
return false;
|
|
|
|
bool salvouComSucesso = false;
|
|
bool eventosGravadosComSucesso = false;
|
|
DateTime agora = DateTime.Now;
|
|
|
|
List<OperacaoSensoriamentoLogErrosModel> eventosSalvos = new List<OperacaoSensoriamentoLogErrosModel>();
|
|
|
|
try
|
|
{
|
|
if (string.IsNullOrWhiteSpace(op.ID))
|
|
return false;
|
|
|
|
// Garante pasta da operação
|
|
string pastaOperacao = Path.Combine(Variaveis.CaminhoOperacoes, op.ID);
|
|
Directory.CreateDirectory(pastaOperacao);
|
|
|
|
// Opcional, mas eu recomendo:
|
|
// garante que o snapshot salvo é o mais novo possível.
|
|
//
|
|
// Se você já chama op.Sensoriamento.AtualizarDados()
|
|
// imediatamente antes de SalvarLogs(), pode remover esse bloco.
|
|
op.AtualizarSensoriamentoSeguro();
|
|
|
|
// AtualizarDados() substitui op.Sensoriamento por um novo snapshot,
|
|
// então pegamos a referência novamente.
|
|
var sen = op.Sensoriamento;
|
|
|
|
if (sen == null)
|
|
return false;
|
|
|
|
// -----------------------------
|
|
// Logs principais
|
|
// -----------------------------
|
|
SalvarLogLineSeNaoNulo("operacao", sen.Operacao?.Clone());
|
|
SalvarLogLineSeNaoNulo("controle", op.Controle?.Clone());
|
|
|
|
// -----------------------------
|
|
// Módulos físicos
|
|
// -----------------------------
|
|
SalvarLogLineSeNaoNulo(T_Code.Mov.ToString(), sen.Movimentacao?.Clone());
|
|
SalvarLogLineSeNaoNulo(T_Code.Dir.ToString(), sen.Direcional?.Clone());
|
|
SalvarLogLineSeNaoNulo(T_Code.Atu.ToString(), sen.Atuador?.Clone());
|
|
SalvarLogLineSeNaoNulo(T_Code.Sen.ToString(), sen.Sensoriamento?.Clone());
|
|
|
|
// -----------------------------
|
|
// Módulos auxiliares / navegação
|
|
// -----------------------------
|
|
SalvarLogLineSeNaoNulo(T_Code.Imu.ToString(), sen.IMU?.Clone());
|
|
SalvarLogLineSeNaoNulo(T_Code.Lvx.ToString(), sen.LivoxLidar?.Clone());
|
|
SalvarLogLineSeNaoNulo(T_Code.Gps.ToString(), sen.Gps?.Clone());
|
|
|
|
// -----------------------------
|
|
// Logs operacionais novos
|
|
// -----------------------------
|
|
SalvarLogLineSeNaoNulo(T_Code.Bat.ToString(), sen.Bateria?.Clone());
|
|
SalvarLogLineSeNaoNulo(T_Code.Trj.ToString(), sen.Trajetoria?.Clone());
|
|
SalvarLogLineSeNaoNulo(T_Code.Npc.ToString(), sen.DadosPerformance?.Clone());
|
|
SalvarLogLineSeNaoNulo("cooler", sen.CoolerControl?.Clone());
|
|
SalvarLogLineSeNaoNulo("base", VariaveisOperacao.PosicaoBase?.Clone());
|
|
|
|
// -----------------------------
|
|
// Workers / operadores
|
|
// -----------------------------
|
|
SalvarLogLineSeNaoNulo("HealthWorker", sen.OperadorSaude?.Clone());
|
|
SalvarLogLineSeNaoNulo("WeedWorker", sen.OperadorErvas?.Clone());
|
|
SalvarLogLineSeNaoNulo("VisualWorker", sen.OperadorVisual?.Clone());
|
|
|
|
// -----------------------------
|
|
// Eventos discretos de saúde/erro
|
|
// Melhor salvar um evento por linha.
|
|
// -----------------------------
|
|
eventosSalvos = op.DrenarEventosPendentes();
|
|
|
|
foreach (var evento in eventosSalvos)
|
|
{
|
|
SalvarLogLine("eventos", evento);
|
|
}
|
|
|
|
eventosGravadosComSucesso = true;
|
|
|
|
// -----------------------------
|
|
// Câmeras
|
|
// -----------------------------
|
|
SalvarLogCameraSolo();
|
|
SalvarLogCameraCaminho();
|
|
|
|
// -----------------------------
|
|
// Marcador de fim, se quiser facilitar análise posterior
|
|
// -----------------------------
|
|
if (Fim)
|
|
{
|
|
SalvarLogLine("fim", new
|
|
{
|
|
Momento = agora,
|
|
OperacaoID = op.ID,
|
|
Fim = true,
|
|
Status = op.Status,
|
|
StatusOperacao = sen.Operacao?.StatusOperacaoAtual
|
|
});
|
|
}
|
|
|
|
// -----------------------------
|
|
// Índice/manifesto dos arquivos da operação
|
|
// -----------------------------
|
|
SalvarArquivoIndiceOperacao(op);
|
|
|
|
op.idxLog++;
|
|
salvouComSucesso = true;
|
|
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Variaveis.MostrarLog("[OperacaoModel.SalvarLogs] Erro ao salvar log: " + ex.Message);
|
|
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
try
|
|
{
|
|
op?.Controle?.TiposControle?.ForEach(x => x.Comandos?.Clear());
|
|
}
|
|
catch
|
|
{
|
|
// Não deixa limpeza de comandos derrubar o log.
|
|
}
|
|
|
|
if (!eventosGravadosComSucesso && eventosSalvos.Any())
|
|
{
|
|
op.ReenfileirarEventosPendentes(eventosSalvos);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SalvarLogLineSeNaoNulo(string categoria, object dados)
|
|
{
|
|
if (dados == null)
|
|
return;
|
|
|
|
SalvarLogLine(categoria, dados);
|
|
}
|
|
|
|
private void SalvarArquivoIndiceOperacao(OperacaoModel op)
|
|
{
|
|
string pastaOperacao = Path.Combine(Variaveis.CaminhoOperacoes, op.ID);
|
|
string arquivoOp = Path.Combine(pastaOperacao, "data.lgop");
|
|
|
|
if (File.Exists(arquivoOp))
|
|
return;
|
|
|
|
var data = new Dictionary<string, object>()
|
|
{
|
|
{ "id", op.ID },
|
|
|
|
{ "operacao", "operacao" },
|
|
{ "controle", "controle" },
|
|
|
|
{ "mov", T_Code.Mov.ToString() },
|
|
{ "dir", T_Code.Dir.ToString() },
|
|
{ "atu", T_Code.Atu.ToString() },
|
|
{ "sen", T_Code.Sen.ToString() },
|
|
|
|
{ "imu", T_Code.Imu.ToString() },
|
|
{ "lvx", T_Code.Lvx.ToString() },
|
|
{ "gps", T_Code.Gps.ToString() },
|
|
|
|
{ "bateria", T_Code.Bat },
|
|
{ "trajetoria", T_Code.Trj },
|
|
{ "performance", T_Code.Npc },
|
|
{ "cooler", "cooler" },
|
|
|
|
{ "healthworker", "HealthWorker" },
|
|
{ "weedworker", "WeedWorker" },
|
|
{ "visualworker", "VisualWorker" },
|
|
|
|
{ "eventos", "eventos" },
|
|
{ "fim", "fim" },
|
|
|
|
{ "cam_caminho", T_Code.Snr.ToString() },
|
|
{
|
|
"cam_solo",
|
|
CameraWorkerService.CamerasSolo
|
|
.Select((x, i) => x.Dispositivo.ToString() + i)
|
|
.ToList()
|
|
}
|
|
};
|
|
|
|
File.WriteAllText(
|
|
arquivoOp,
|
|
JsonConvert.SerializeObject(data, Formatting.Indented)
|
|
);
|
|
}
|
|
|
|
private void SalvarLogCameraSolo()
|
|
{
|
|
var op = this;
|
|
|
|
var cameras = CameraWorkerService.CamerasSolo.ToList();
|
|
for (int i = 0; i < cameras.Count; i++)
|
|
{
|
|
var Camera = cameras[i];
|
|
string camera_name = $"{Camera.Dispositivo}{i}";
|
|
string Caminho = Variaveis.CaminhoOperacoes + op.ID + "/" + camera_name;
|
|
if (!Directory.Exists(Caminho))
|
|
{
|
|
Directory.CreateDirectory(Caminho);
|
|
}
|
|
|
|
string nome = op.idxLog.ToString();
|
|
var frames_salvar = new List<TipoFrameCamera>() { TipoFrameCamera.Rgb, TipoFrameCamera.Segmentacao };
|
|
if (op.Parametros.Controle.RegistrarDadosPosProcessamento) frames_salvar.Add(TipoFrameCamera.PosProcessamento);
|
|
Camera.SaveFrames(frames_salvar, nome, Caminho);
|
|
|
|
var cameras_conectadas = JsonConvert.DeserializeObject<Dictionary<string, object>>(RedisService.Get(CtxKey.DadosCameras));
|
|
bool conectada = cameras_conectadas.ContainsKey(Camera?.Id ?? "");
|
|
if (conectada)
|
|
{
|
|
var cam_data = JsonConvert.DeserializeObject<Dictionary<string, object>>(RedisService.Get(RedisService.CamKey(Camera.Id)));
|
|
SalvarLogLine(camera_name, cam_data);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SalvarLogCameraCaminho()
|
|
{
|
|
var op = this;
|
|
|
|
var Camera = CameraWorkerService.CameraCaminho;
|
|
if (Camera == null)
|
|
return;
|
|
|
|
string Caminho = Variaveis.CaminhoOperacoes + op.ID + "/" + Camera.Dispositivo;
|
|
if (!Directory.Exists(Caminho))
|
|
{
|
|
Directory.CreateDirectory(Caminho);
|
|
}
|
|
|
|
string nome = op.idxLog.ToString();
|
|
var frames_salvar = new List<TipoFrameCamera>() { TipoFrameCamera.Rgb, TipoFrameCamera.Segmentacao };
|
|
if (op.Parametros.Controle.RegistrarDadosPosProcessamento) frames_salvar.AddRange(new List<TipoFrameCamera>() { TipoFrameCamera.PosProcessamento, TipoFrameCamera.Heatmap });
|
|
Camera.SaveFrames(frames_salvar, nome, Caminho);
|
|
|
|
var cameras_conectadas = JsonConvert.DeserializeObject<Dictionary<string, object>>(RedisService.Get(CtxKey.DadosCameras));
|
|
bool conectada = cameras_conectadas.ContainsKey(Camera?.Id ?? "");
|
|
if (conectada)
|
|
{
|
|
var cam_data = JsonConvert.DeserializeObject<Dictionary<string, object>>(RedisService.Get(RedisService.CamKey(Camera.Id)));
|
|
SalvarLogLine(Camera.Dispositivo.ToString(), cam_data);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
private static readonly object _lockLog = new object();
|
|
|
|
const long TAMANHO_MAX_LOG_BYTES = 50 * 1024 * 1024; // 50 MB
|
|
|
|
private void SalvarLogLine<T>(string arquivo, T objeto)
|
|
{
|
|
var op = this;
|
|
|
|
try
|
|
{
|
|
var pasta = Path.Combine(
|
|
Variaveis.CaminhoOperacoes,
|
|
op.ID
|
|
);
|
|
|
|
if (!Directory.Exists(pasta))
|
|
Directory.CreateDirectory(pasta);
|
|
|
|
string json = JsonConvert.SerializeObject(objeto, Formatting.None);
|
|
|
|
lock (_lockLog)
|
|
{
|
|
string caminhoAtual = op.ObterOuCriarArquivoLogAtual(pasta, arquivo, json);
|
|
|
|
File.AppendAllText(caminhoAtual, json + Environment.NewLine);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Erro ao salvar log '{arquivo}': {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private string ObterOuCriarArquivoLogAtual(string pasta, string arquivoBase, string proximoJson)
|
|
{
|
|
var op = this;
|
|
|
|
var arquivosExistentes = Directory
|
|
.GetFiles(pasta, $"{arquivoBase}_*.jsonl")
|
|
.OrderBy(x => x, StringComparer.OrdinalIgnoreCase)
|
|
.ToList();
|
|
|
|
string ultimoArquivo = arquivosExistentes.LastOrDefault();
|
|
|
|
if (string.IsNullOrWhiteSpace(ultimoArquivo))
|
|
return op.CriarNovoArquivoLog(pasta, arquivoBase, 1);
|
|
|
|
var info = new FileInfo(ultimoArquivo);
|
|
|
|
long tamanhoAposAppend =
|
|
info.Exists
|
|
? info.Length + System.Text.Encoding.UTF8.GetByteCount(proximoJson + Environment.NewLine)
|
|
: System.Text.Encoding.UTF8.GetByteCount(proximoJson + Environment.NewLine);
|
|
|
|
if (tamanhoAposAppend > TAMANHO_MAX_LOG_BYTES)
|
|
{
|
|
int proximoIdx = op.ExtrairIndiceArquivo(ultimoArquivo, arquivoBase) + 1;
|
|
return op.CriarNovoArquivoLog(pasta, arquivoBase, proximoIdx);
|
|
}
|
|
|
|
return ultimoArquivo;
|
|
}
|
|
|
|
private string CriarNovoArquivoLog(string pasta, string arquivoBase, int idx)
|
|
{
|
|
string horario = DateTime.Now.ToString("yyyyMMdd_HHmmss", CultureInfo.InvariantCulture);
|
|
string nomeArquivo = $"{arquivoBase}_{idx:0000}_{horario}.jsonl";
|
|
string caminho = Path.Combine(pasta, nomeArquivo);
|
|
|
|
// já cria vazio para “reservar” o nome
|
|
using (File.Create(caminho)) { }
|
|
|
|
return caminho;
|
|
}
|
|
|
|
private int ExtrairIndiceArquivo(string caminhoArquivo, string arquivoBase)
|
|
{
|
|
try
|
|
{
|
|
string nome = Path.GetFileNameWithoutExtension(caminhoArquivo);
|
|
|
|
// esperado: {arquivo}_{idx}_{horario}
|
|
string prefixo = arquivoBase + "_";
|
|
if (!nome.StartsWith(prefixo, StringComparison.OrdinalIgnoreCase))
|
|
return 0;
|
|
|
|
string restante = nome.Substring(prefixo.Length);
|
|
string[] partes = restante.Split('_');
|
|
|
|
if (partes.Length < 2)
|
|
return 0;
|
|
|
|
if (int.TryParse(partes[0], out int idx))
|
|
return idx;
|
|
|
|
return 0;
|
|
}
|
|
catch
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region FORMULARIO
|
|
|
|
public void AbrirForm()
|
|
{
|
|
var op = this;
|
|
if (op.Sensoriamento.Operacao.OperacaoLiberada)
|
|
{
|
|
frmOperacao =
|
|
Parametros?.Modo == ModoOperacao.Manual ? new frmOperacaoManual() :
|
|
Parametros?.Modo == ModoOperacao.MapaGPS ? new frmOperacaoMapaGPS() :
|
|
new Form();
|
|
|
|
frmOperacao.Show();
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show(op.Sensoriamento.Operacao.ErroOperacaoLiberada, "Conexão de módulos pendentes", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
}
|
|
}
|
|
|
|
public string TextoFormOperacao(string ModoNome)
|
|
{
|
|
var op = this;
|
|
var statusAtual = op.Sensoriamento.Operacao.StatusOperacaoAtual;
|
|
|
|
if (statusAtual == StatusOperacao.Parametrizando)
|
|
{
|
|
return "Operação " + ModoNome + " - Parametrização";
|
|
}
|
|
else if (statusAtual == StatusOperacao.Aguardando)
|
|
{
|
|
double segundosAguardados = op.Sensoriamento?.Operacao?.TempoAguardandoSeg ?? 0;
|
|
double tempoTotalEspera = Math.Max(0, op.TempoIniciarOperacao);
|
|
|
|
double segundosRestantes = Math.Max(0, tempoTotalEspera - segundosAguardados);
|
|
|
|
int segundosTela = (int)Math.Ceiling(segundosRestantes);
|
|
string plural = segundosTela == 1 ? "" : "s";
|
|
|
|
return $"Operação {ModoNome} - Iniciando em {segundosTela} segundo{plural}...";
|
|
}
|
|
else if (statusAtual == StatusOperacao.Concluido)
|
|
{
|
|
return "Operação " + ModoNome + " - Concluída";
|
|
}
|
|
else if (statusAtual == StatusOperacao.EmAndamento)
|
|
{
|
|
return "Operação " + ModoNome + " - Em andamento";
|
|
}
|
|
else if (statusAtual == StatusOperacao.Parado)
|
|
{
|
|
return "Operação " + ModoNome + " - Parado";
|
|
}
|
|
else
|
|
{
|
|
return "Operação " + ModoNome;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DIAGNOSTICO
|
|
|
|
public static void PopularTreeView(TreeView treeView, List<ManagerWorkerMessageResponseModulosPendentesModel> modulos)
|
|
{
|
|
treeView.Font = new Font("Consolas", 10);
|
|
treeView.Nodes.Clear();
|
|
|
|
foreach (var modulo in modulos)
|
|
{
|
|
string nomeModulo = $"{modulo.modulo} {modulo.status} (Saúde: {modulo.saude:0}%)";
|
|
TreeNode nodoModulo = new TreeNode(nomeModulo);
|
|
|
|
if (modulo.saude_individual.Any())
|
|
{
|
|
foreach (var item in modulo.saude_individual.Where(x => x.em_uso))
|
|
{
|
|
string nomeItem = $"{item.label} ({item.id}) {item.status} (Saúde: {item.saude:0}%)";
|
|
TreeNode nodoItem = new TreeNode(nomeItem);
|
|
|
|
// Adiciona os motivos normais (de saúde)
|
|
foreach (var motivo in item.motivos)
|
|
{
|
|
nodoItem.Nodes.Add(new TreeNode(motivo));
|
|
}
|
|
|
|
// Agrupamento das condições operacionais (se houver)
|
|
if (item.condicoes_operacionais != null && item.condicoes_operacionais.Count > 0)
|
|
{
|
|
TreeNode nodoCondicoes = new TreeNode("Condições Operacionais");
|
|
|
|
foreach (var cond in item.condicoes_operacionais)
|
|
{
|
|
string textoCond = $"{cond.descricao} (Valor: {cond.valor}, Severidade: {cond.severidade:0}%)";
|
|
nodoCondicoes.Nodes.Add(new TreeNode(textoCond));
|
|
}
|
|
|
|
nodoItem.Nodes.Add(nodoCondicoes);
|
|
}
|
|
|
|
nodoModulo.Nodes.Add(nodoItem);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Adiciona os motivos normais (de saúde)
|
|
foreach (var motivo in modulo.motivos)
|
|
{
|
|
nodoModulo.Nodes.Add(new TreeNode(motivo));
|
|
}
|
|
}
|
|
if (modulo.condicoes_operacionais?.Any() ?? false)
|
|
{
|
|
// Agrupamento das condições operacionais (se houver)
|
|
if (modulo.condicoes_operacionais != null && modulo.condicoes_operacionais.Count > 0)
|
|
{
|
|
TreeNode nodoCondicoes = new TreeNode("Condições Operacionais");
|
|
|
|
foreach (var cond in modulo.condicoes_operacionais)
|
|
{
|
|
string textoCond = $"{cond.descricao} (Valor: {cond.valor}, Severidade: {cond.severidade:0}%)";
|
|
nodoCondicoes.Nodes.Add(new TreeNode(textoCond));
|
|
}
|
|
|
|
nodoModulo.Nodes.Add(nodoCondicoes);
|
|
}
|
|
}
|
|
|
|
treeView.Nodes.Add(nodoModulo);
|
|
}
|
|
|
|
treeView.ExpandAll();
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
|
|
public class OperacaoControleModel
|
|
{
|
|
public DateTime Momento { get; set; }
|
|
public double Angulo { get; set; }
|
|
public int heartbeat { get; set; } = 1;
|
|
public DateTime ticks_sem_resposta { get; set; } = DateTime.MinValue;
|
|
public int RPM_SP
|
|
{
|
|
get
|
|
{
|
|
return Convert.ToInt32(VariaveisEquipamento.RPM_Max_Roda * (PercentualVelocidadeSP / 100.0));
|
|
}
|
|
}
|
|
public int RPM_Motor
|
|
{
|
|
get
|
|
{
|
|
return Convert.ToInt32(RPM_SP * VariaveisEquipamento.RelacaoRPM);
|
|
}
|
|
}
|
|
private double _pctVelSp;
|
|
public double PercentualVelocidadeSP
|
|
{
|
|
get
|
|
{
|
|
return _pctVelSp;
|
|
}
|
|
set
|
|
{
|
|
_pctVelSp = value;
|
|
}
|
|
}
|
|
public double PercentualVelocidadeSPKmh
|
|
{
|
|
get
|
|
{
|
|
return FuncoesMatematicas.ConverteMsParaKmh(FuncoesMatematicas.CalculaVelocidadeMsPercentual(PercentualVelocidadeSP));
|
|
}
|
|
}
|
|
public bool EmFreio { get; set; } = false;
|
|
public double AlturaBarra { get; set; }
|
|
public TipoMovimentoDirecional TipoMovimento { get; set; } = TipoMovimentoDirecional.Diagnostico;
|
|
public List<OperacaoControleTipoModel> TiposControle { get; set; } = new List<OperacaoControleTipoModel>();
|
|
public List<MPCSimulacaoModel> SimulacaoMPC { get; set; } = new List<MPCSimulacaoModel>();
|
|
public double Latencia { get; set; }
|
|
public double ErroLateral { get; set; } = 0.0;
|
|
public Dictionary<string, ManagerWorkerMessageResponseDebugCustoModel> DebugCustoMpc { get; set; } = new Dictionary<string, ManagerWorkerMessageResponseDebugCustoModel>();
|
|
public List<string> Motivos { get; set; } = new List<string>();
|
|
|
|
public void Reiniciar()
|
|
{
|
|
PercentualVelocidadeSP = 0;
|
|
Angulo = 0;
|
|
EmFreio = false;
|
|
TiposControle.ForEach(x =>
|
|
{
|
|
x.DirecaoAtual = Direcao.Parado;
|
|
x.UltimaDirecao = Direcao.Parado;
|
|
});
|
|
}
|
|
|
|
public OperacaoControleModel Clone()
|
|
{
|
|
var clone = new OperacaoControleModel()
|
|
{
|
|
Momento = Momento,
|
|
|
|
Angulo = Angulo,
|
|
PercentualVelocidadeSP = PercentualVelocidadeSP,
|
|
AlturaBarra = AlturaBarra,
|
|
heartbeat = heartbeat,
|
|
ticks_sem_resposta = ticks_sem_resposta,
|
|
Latencia = Latencia,
|
|
EmFreio = EmFreio,
|
|
ErroLateral = ErroLateral,
|
|
TiposControle = TiposControle?.Select(x => new OperacaoControleTipoModel()
|
|
{
|
|
Tipo = x.Tipo,
|
|
DelayEnvioComandoBase = x.DelayEnvioComandoBase,
|
|
DelayEnvioComando = x.DelayEnvioComando,
|
|
DelayEnvioComandoExtra = x.DelayEnvioComandoExtra,
|
|
UltimoComando = x.UltimoComando,
|
|
Comandos = new List<string>(x.Comandos ?? new List<string>()),
|
|
DirecaoAtual = x.DirecaoAtual,
|
|
UltimaDirecao = x.UltimaDirecao
|
|
}).ToList() ?? new List<OperacaoControleTipoModel>(),
|
|
SimulacaoMPC = new List<MPCSimulacaoModel>(SimulacaoMPC ?? new List<MPCSimulacaoModel>()),
|
|
DebugCustoMpc = new Dictionary<string, ManagerWorkerMessageResponseDebugCustoModel>(DebugCustoMpc ?? new Dictionary<string, ManagerWorkerMessageResponseDebugCustoModel>()),
|
|
Motivos = new List<string>(Motivos ?? new List<string>())
|
|
};
|
|
|
|
return clone;
|
|
}
|
|
}
|
|
|
|
public class OperacaoControleTipoModel
|
|
{
|
|
public T_Code Tipo { get; set; }
|
|
public int DelayEnvioComandoBase { get; set; }
|
|
public int DelayEnvioComando { get; set; }
|
|
public int DelayEnvioComandoExtra { get; set; }
|
|
public DateTime UltimoComando { get; set; }
|
|
public List<string> Comandos { get; set; }
|
|
public Direcao DirecaoAtual { get; set; } = Direcao.Parado;
|
|
public Direcao UltimaDirecao { get; set; } = Direcao.Parado;
|
|
}
|
|
|
|
public class OperacaoModulosMandatoriosModel
|
|
{
|
|
public T_Code Dispositivo { get; set; }
|
|
public bool Mandatorio { get; set; }
|
|
public bool Utilizar { get; set; }
|
|
public bool Conectado { get; set; }
|
|
public Dictionary<string, (bool, bool)> ComponentesEmUso { get; set; }
|
|
}
|
|
|
|
public class OperacaoParametrosMandatoriosModel
|
|
{
|
|
public ParametrosOperacao Parametro { get; set; }
|
|
public bool Mandatorio { get; set; }
|
|
public bool Utilizar { get; set; }
|
|
}
|
|
|
|
public class OperacaoComandoBaseModel
|
|
{
|
|
public DateTime Momento { get; set; }
|
|
public BotoesJoystick Tecla { get; set; }
|
|
public bool Solto { get; set; }
|
|
public T_Code Dispositivo { get; set; }
|
|
public bool Emergencia { get; set; }
|
|
public bool Pausa { get; set; }
|
|
public string _comp_id { get; set; }
|
|
public dynamic _comp_value { get; set; }
|
|
public OperacaoParametrosModel Parametros { get; set; }
|
|
public OperacaoComandoBaseControleModel Controle { get; set; }
|
|
}
|
|
|
|
public class OperacaoComandoBaseControleModel
|
|
{
|
|
public CanMessagePosicaoDados Comando { get; set; } = CanMessagePosicaoDados.Command1;
|
|
public double? PercentualVelocidadeSP { get; set; }
|
|
public double? AnguloSP { get; set; }
|
|
public TipoMovimentoDirecional? TipoMovimentoDirecional { get; set; }
|
|
public bool? EmFreio { get; set; }
|
|
public bool? Estado { get; set; }
|
|
public double? Altura { get; set; }
|
|
public double? Potencia { get; set; }
|
|
public double? Pressao { get; set; }
|
|
}
|
|
|
|
|
|
public class OperacaoDadosModel
|
|
{
|
|
public string id { get; set; }
|
|
public string operacao { get; set; }
|
|
public string dir { get; set; }
|
|
public string mov { get; set; }
|
|
public string atu { get; set; }
|
|
public string sen { get; set; }
|
|
public string cam_caminho { get; set; }
|
|
public List<string> cam_solo { get; set; }
|
|
}
|
|
|
|
public class OperacaoSensoriamentoConjuntoModel
|
|
{
|
|
public OperacaoSensoriamentoConjuntoModel(OperacaoModel operaao)
|
|
{
|
|
op = operaao;
|
|
}
|
|
public OperacaoModel op { get; private set; }
|
|
|
|
public DateTime Momento { get; set; }
|
|
|
|
// Operacao
|
|
public OperacaoSensoriamentoLogModel Operacao { get; set; } = new OperacaoSensoriamentoLogModel();
|
|
public void AtualizarOperacao(DateTime agora)
|
|
{
|
|
if (op == null) return;
|
|
|
|
op.Controle.Motivos = RedisService.GetField<List<string>>(CtxKey.DadosControle, "motivos", new List<string>());
|
|
|
|
double tempoDecorridoSeg = 0;
|
|
if (Operacao.DataInicio != DateTime.MinValue)
|
|
{
|
|
DateTime fim = Operacao.DataFim != DateTime.MinValue ? Operacao.DataFim : agora;
|
|
tempoDecorridoSeg = Math.Max(0, (fim - Operacao.DataInicio).TotalSeconds);
|
|
}
|
|
|
|
double tempoAguardandoRaw = RedisService.GetField<double>(CtxKey.DadosOperacao, "tempo_aguardando", 0.0);
|
|
double tempoAguardarInicio = RedisService.GetField<double>(CtxKey.DadosOperacao, "tempo_aguardar_inicio_operacao", op.TempoIniciarOperacao);
|
|
double agoraUnix = DateTimeOffset.Now.ToUnixTimeMilliseconds() / 1000.0;
|
|
double tempoAguardandoSeg;
|
|
if (tempoAguardandoRaw > 1_000_000_000)
|
|
{
|
|
// Redis está mandando timestamp Unix de início da espera.
|
|
tempoAguardandoSeg = Math.Max(0.0, agoraUnix - tempoAguardandoRaw);
|
|
}
|
|
else
|
|
{
|
|
// Compatibilidade: caso algum fluxo antigo mande duração em segundos.
|
|
tempoAguardandoSeg = Math.Max(0.0, tempoAguardandoRaw);
|
|
}
|
|
|
|
op.TempoIniciarOperacao = Math.Max(0, Convert.ToInt32(Math.Round(tempoAguardarInicio)));
|
|
|
|
var operacaoAtualizada = new OperacaoSensoriamentoLogModel()
|
|
{
|
|
Momento = agora,
|
|
Modo = op.Parametros?.Modo ?? ModoOperacao.NaoDefinido,
|
|
ControleAutomatico = op.Parametros?.ControleAutomatico ?? false,
|
|
Status = op.Status,
|
|
StatusOperacaoAnterior = Operacao.StatusOperacaoAnterior,
|
|
OperacaoIniciada = Operacao.OperacaoIniciada,
|
|
Emergencia = Operacao.Emergencia,
|
|
Pausa = Operacao.Pausa,
|
|
Calibrando = Operacao.Calibrando,
|
|
Finalizando = Operacao.Finalizando,
|
|
DataInicio = Operacao.DataInicio,
|
|
DataFim = Operacao.DataFim,
|
|
TempoDecorridoSeg = tempoDecorridoSeg,
|
|
TempoAguardandoSeg = tempoAguardandoSeg,
|
|
TipoCanAtivo = CanManager.TipoServico,
|
|
|
|
OperacaoLiberada = RedisService.GetField(CtxKey.DadosOperacao, "liberado", false),
|
|
OperacaoConfigurada = RedisService.GetField(CtxKey.DadosOperacao, "configurado", false),
|
|
ErroOperacaoLiberada = RedisService.GetField<string>(CtxKey.DadosOperacao, "motivo_nao_liberado"),
|
|
OperacaoLiberacaoDebug = RedisService.GetField<JObject>(CtxKey.DadosOperacao, "operacao_liberacao_debug"),
|
|
StatusOperacaoAtual = (StatusOperacao)RedisService.GetField<int>(CtxKey.DadosOperacao, "status", 0),
|
|
|
|
ModulosMandatorios = new List<OperacaoModulosMandatoriosModel>(op.Parametros.ModulosMandatorios ?? new List<OperacaoModulosMandatoriosModel>()),
|
|
ParametrosMandatorios = new List<OperacaoParametrosMandatoriosModel>(op.Parametros.ParametrosMandatorios ?? new List<OperacaoParametrosMandatoriosModel>()),
|
|
DispositivosMapeados = new List<DispositivoDetalhesModel>(SerialService.DispositivosMapeados),
|
|
ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>(Operacao.ModsCalibragem ?? new Dictionary<T_Code, Dictionary<string, bool>>()),
|
|
ModsCalibragemView = Operacao.ModsCalibragem?.ToDictionary(x => x.Key.ToString(), x => new Dictionary<string, bool>(x.Value ?? new Dictionary<string, bool>())) ?? new Dictionary<string, Dictionary<string, bool>>(),
|
|
};
|
|
|
|
if (operacaoAtualizada.StatusOperacaoAtual != Operacao.StatusOperacaoAnterior)
|
|
{
|
|
AudioAlertaService.AlertaSonoroPorStatus(operacaoAtualizada.StatusOperacaoAtual);
|
|
}
|
|
operacaoAtualizada.StatusOperacaoAnterior = operacaoAtualizada.StatusOperacaoAtual;
|
|
|
|
var saude = OperadorSaude.ModulosSaude;
|
|
var saudeAnterior = new List<ManagerWorkerMessageResponseModulosPendentesModel>(saude ?? new List<ManagerWorkerMessageResponseModulosPendentesModel>());
|
|
saude = RedisService.GetField<ManagerWorkerMessageResponseModulosPendentesModel[]>(CtxKey.DadosOperacao, "status_modulos")?.ToList() ?? new List<ManagerWorkerMessageResponseModulosPendentesModel>();
|
|
|
|
foreach (var mod in saude)
|
|
{
|
|
var mod_ant = saudeAnterior.FirstOrDefault(x => x.modulo == mod.modulo);
|
|
if (mod.status != mod_ant?.status)
|
|
{
|
|
string msg = mod.motivos.Any() ? string.Join("; ", mod.motivos) : $"{mod.status} ({mod.saude:0}%)";
|
|
string msg2 = mod.condicoes_operacionais.Any() ? string.Join("; ", mod.condicoes_operacionais.Select(x => x.descricao)) : null;
|
|
InserirLog(mod.modulo, mod.status, mod.saude, msg, condicoes: msg2);
|
|
}
|
|
if (mod.saude_individual.Any())
|
|
{
|
|
foreach (var ind in mod.saude_individual.Where(x => x.em_uso))
|
|
{
|
|
var ind_ant = saudeAnterior.FirstOrDefault(x => x.modulo == mod.modulo && x.saude_individual.Any(y => y.id == ind.id))?.saude_individual?.FirstOrDefault(x => x.id == ind.id);
|
|
if (ind.status != ind_ant?.status)
|
|
{
|
|
string msg = ind.motivos.Any() ? string.Join("; ", ind.motivos) : $"{ind.status} ({ind.saude:0}%)";
|
|
string msg2 = ind.condicoes_operacionais.Any() ? string.Join("; ", ind.condicoes_operacionais.Select(x => x.descricao)) : null;
|
|
InserirLog(mod.modulo, ind.status, ind.saude, msg, condicoes: msg2, id: ind.label);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
double saude_geral = saude.DefaultIfEmpty().Average(x => x?.saude ?? 0);
|
|
operacaoAtualizada.Status =
|
|
!operacaoAtualizada.OperacaoLiberada ? StatusModulo.Falha :
|
|
saude_geral <= 0.0 ? StatusModulo.Desconectado :
|
|
saude_geral < 80.0 ? StatusModulo.Alerta :
|
|
StatusModulo.Operante;
|
|
|
|
Operacao = operacaoAtualizada;
|
|
}
|
|
|
|
// Atu
|
|
public AtuadorLogModel Atuador { get; set; } = new AtuadorLogModel();
|
|
public void AtualizarAtuador(DateTime agora)
|
|
{
|
|
if (op == null) return;
|
|
|
|
var dadosAtu = op.DispAtu?.Dados;
|
|
var pControle = op.Parametros?.Controle;
|
|
var bombaLinha = dadosAtu?.BombaPressurizadora;
|
|
var reservatorio = dadosAtu?.ContadorCarga;
|
|
|
|
if (dadosAtu == null)
|
|
{
|
|
Atuador = new AtuadorLogModel()
|
|
{
|
|
Momento = agora,
|
|
Inicializado = false,
|
|
ConexaoAtiva = false
|
|
};
|
|
return;
|
|
}
|
|
|
|
Atuador = new AtuadorLogModel()
|
|
{
|
|
Momento = agora,
|
|
|
|
Inicializado = dadosAtu.ConexaoAtiva,
|
|
ConexaoAtiva = dadosAtu.ConexaoAtiva,
|
|
LatenciaLoop = dadosAtu.DadosLeitura?.LatenciaLoop ?? 0,
|
|
UltimoComandoRespondido = dadosAtu.DadosLeitura?.UltimoComandoRespondido ?? dadosAtu.DadosLeitura?.Momento ?? DateTime.MinValue,
|
|
|
|
QtdCamerasSolo = CameraWorkerService.CamerasSolo.Count,
|
|
QuantidadeBicos = op.Parametros?.QtdBicos ?? VariaveisEquipamento.QuantidadeBicosPulverizadores,
|
|
CapacidadeReservatorio = VariaveisEquipamento.CapacidadeReservatorio,
|
|
|
|
MassaReservatorio = dadosAtu.ContadorCarga?.MassaAtual_Kg ?? reservatorio?.MassaAtual_Kg ?? 0,
|
|
VolumeReservatorio = dadosAtu.ContadorCarga?.VolumeAtual_L ?? reservatorio?.VolumeAtual_L ?? 0,
|
|
PercentualReservatorio = dadosAtu.ContadorCarga?.PercentualAtual ?? reservatorio?.PercentualAtual ?? 0,
|
|
|
|
HerbicidaConsumido = reservatorio?.VolumeConsumidoTotal_L ?? 0,
|
|
HerbicidaConsumidoOperacao = reservatorio?.VolumeConsumidoOperacao_L ?? 0,
|
|
PercentualHerbicidaConsumido = dadosAtu.ContadorCarga?.PercentualConsumidoTotal ?? reservatorio?.PercentualConsumidoTotal ?? 0,
|
|
PercentualHerbicidaConsumidoOperacao = dadosAtu.ContadorCarga?.PercentualConsumidoOperacao ?? reservatorio?.PercentualConsumidoOperacao ?? 0,
|
|
|
|
HerbicidaPorAtuacao = dadosAtu.ContadorCarga?.HerbicidaPorAtuacao_L ?? 0,
|
|
HerbicidaPorErva = reservatorio?.HerbicidaPorAtuacao_L ?? dadosAtu.ContadorCarga?.HerbicidaPorAtuacao_L ?? 0,
|
|
|
|
ErvasNoRadar = OperadorErvas.Analise?.ervas_no_radar ?? false,
|
|
PercentualErvasNoRadar = OperadorErvas?.Analise?.percentual_ervas_no_radar ?? 0,
|
|
PercentualErvasTerreno = dadosAtu.PercentualErvasTerreno,
|
|
|
|
PressaoLinha_SP = pControle?.AtuPressaoLinha ?? 0,
|
|
PressaoLinha = dadosAtu.PressaoLinha,
|
|
PressaoLinhaCalc = dadosAtu.PressaoLinhaCalc,
|
|
PressaoAtualBomba = dadosAtu.BombaPressurizadora?._PressaoAtual ?? 0,
|
|
|
|
VazaoFluxoMLpSInstantanea = dadosAtu.VazaoFluxoMLpSInstantanea,
|
|
VazaoFluxoMLpSInstantaneaCorrigida = dadosAtu.VazaoFluxoMLpSInstantaneaCorrigida,
|
|
VazaoFluxoMLpSMedia = dadosAtu.VazaoMediaMLs,
|
|
VolumeVazaoML = dadosAtu.VolumeVazadoML,
|
|
|
|
BombaLigada = bombaLinha?.ComandoAtuar ?? false,
|
|
ComandoBomba = bombaLinha?.ComandoAtuar ?? false,
|
|
LeituraComandoBomba = bombaLinha?._EstadoLeitura == Estado.Ligado,
|
|
|
|
// Eu manteria os dois, mas tentaria fazer ambos apontarem para a leitura real final.
|
|
PotenciaBomba = FuncoesMatematicas.Clamp(bombaLinha?._PotenciaFinal ?? bombaLinha?._Potencia ?? 0, 0, 100),
|
|
LeituraPotenciaBomba = FuncoesMatematicas.Clamp(bombaLinha?._PotenciaFinal ?? bombaLinha?._Potencia ?? 0, 0, 100),
|
|
|
|
QtdBicosLigados = bombaLinha?._QtdBicosLigados ?? 0,
|
|
PotenciaFeedForward = bombaLinha?._PotenciaFeedForwared ?? 0,
|
|
PotenciaFinal = bombaLinha?._PotenciaFinal ?? 0,
|
|
PressaoSensor = bombaLinha?._PressaoSensor ?? 0,
|
|
PressaoSPControle = bombaLinha?._PressaoSPControle ?? 0,
|
|
|
|
PressaoSPForaDoMapa = bombaLinha?._PressaoSPForaDoMapa ?? false,
|
|
FluxoInsuficiente = bombaLinha?._FluxoInsuficiente ?? false,
|
|
RecuperacaoFluxoAtiva = bombaLinha?._RecuperacaoFluxoAtiva ?? false,
|
|
CavitacaoSuspeita = bombaLinha?._CavitacaoSuspeita ?? false,
|
|
Cavitada = bombaLinha?._Cavitada ?? false,
|
|
CorteSegurancaAtivo = bombaLinha?._CorteSegurancaAtivo ?? false,
|
|
PressaoSPLimitadoPorCapacidade = bombaLinha?._PressaoSPLimitadoPorCapacidade ?? false,
|
|
|
|
TempoPulverizadorAtuado = dadosAtu.TempoAtuado,
|
|
TempoBombaAtuada = dadosAtu.TempoAtuado,
|
|
|
|
BombaCavitada = dadosAtu.Conectado && (bombaLinha?._Cavitada ?? false),
|
|
|
|
ModoControleAgitador = pControle?.AtuAgitadorModo ?? ModoAgitadorCalda.SemAgitacao,
|
|
PotenciaAgitador = dadosAtu.AgitadorDeCalda?.PotenciaMediaAtiva ?? 0,
|
|
|
|
AnguloBarraEsquerda = dadosAtu.AnguloBarraEsquerda,
|
|
AnguloBarraDireita = dadosAtu.AnguloBarraDireita,
|
|
|
|
LPorMetro = reservatorio?.LPorMetro ?? 0,
|
|
LPorMinuto = reservatorio?.LPorMinuto ?? 0,
|
|
TempoEstimadoRestanteMinutos = reservatorio?.TempoEstimadoMinutosPulverizando ?? 0,
|
|
DistanciaEstimadaRestanteMetros = reservatorio?.DistanciaEstimadaRestantePulverizando_m ?? 0,
|
|
|
|
Iniciados =
|
|
dadosAtu.Sensores.Select(s => new { s.ID, s.Inicializado })
|
|
.Union(dadosAtu.BicosPulverizadores.Select(b => new { b.ID, b.Inicializado }))
|
|
.Union(dadosAtu.BombasPressurizadoras.Select(b => new { b.ID, b.Inicializado }))
|
|
.ToDictionary(x => x.ID, x => x.Inicializado),
|
|
|
|
Bicos = dadosAtu.BicosPulverizadores.Select(bico => new AtuadorBicoLogModel()
|
|
{
|
|
ID = bico.ID,
|
|
Inicializado = bico.Inicializado,
|
|
Comandar = bico.Comandar,
|
|
Atuado = bico.ComandoAtuar,
|
|
MediaNivelFluxo = bico.VazaoMediaMLs,
|
|
Posicao = bico.Posicao,
|
|
StatusBico = bico._EstadoLeitura == Estado.Ligado,
|
|
Atuacoes = bico.Atuacoes,
|
|
TempoAtuado = bico.TempoAtuado,
|
|
AnguloAbertura = bico.AnguloAbertura,
|
|
ComMovimento = bico.ComMovimento,
|
|
AnguloControle = bico.AnguloControle
|
|
}).ToList()
|
|
};
|
|
}
|
|
|
|
// Sen
|
|
public SensoriamentoLogModel Sensoriamento { get; set; } = new SensoriamentoLogModel();
|
|
public void AtualizarSensoriamento(DateTime agora)
|
|
{
|
|
if (op == null) return;
|
|
|
|
void AtualizarResumo(SensoriamentoLogModel destino)
|
|
{
|
|
destino.TotalSensores = destino.Sensores.Count;
|
|
destino.SensoresInicializados = destino.Sensores.Count(x => x.Inicializado);
|
|
destino.SensoresAferindo = destino.Sensores.Count(x => x.Aferir);
|
|
destino.SensoresMandatorios = destino.Sensores.Count(x => x.Mandatorio);
|
|
destino.SensoresMandatoriosOk = destino.Sensores.Count(x => x.Mandatorio && x.Liberado);
|
|
|
|
destino.TotalReles = destino.Reles.Count;
|
|
destino.RelesInicializados = destino.Reles.Count(x => x.Inicializado);
|
|
destino.RelesControlando = destino.Reles.Count(x => x.Controlar);
|
|
|
|
destino.TotalServos = destino.Servos.Count;
|
|
destino.ServosInicializados = destino.Servos.Count(x => x.Inicializado);
|
|
destino.ServosControlando = destino.Servos.Count(x => x.Controlar);
|
|
|
|
destino.TotalSinaleiros = destino.Sinaleiros.Count;
|
|
destino.SinaleirosInicializados = destino.Sinaleiros.Count(x => x.Inicializado);
|
|
destino.SinaleirosControlando = destino.Sinaleiros.Count(x => x.Controlar);
|
|
|
|
var leiturasHealth = destino.Sensores
|
|
.SelectMany(x => x.Leituras)
|
|
.Concat(destino.Sinaleiros.SelectMany(x => x.Leituras))
|
|
.Concat(destino.Reles.SelectMany(x => x.Leituras))
|
|
.Concat(destino.Servos.SelectMany(x => x.Leituras))
|
|
.Where(x => x.AnaliseHealth)
|
|
.ToList();
|
|
|
|
destino.LeiturasHealthTotal = leiturasHealth.Count;
|
|
destino.LeiturasHealthOk = leiturasHealth.Count(x => x.DentroFaixa == true);
|
|
destino.LeiturasHealthForaFaixa = leiturasHealth.Count(x => x.DentroFaixa == false);
|
|
}
|
|
|
|
SensoriamentoSensorLogModel CriarSensor(SensorModel sensor)
|
|
{
|
|
var ultimaLeitura = sensor?.UltimaLeitura ?? DateTime.MinValue;
|
|
|
|
return new SensoriamentoSensorLogModel
|
|
{
|
|
ID = sensor?.ID,
|
|
ID_Num = sensor?.ID_Num ?? 0,
|
|
Descricao = sensor?.Descricao,
|
|
Componente = sensor?.Componente ?? default(S_Code),
|
|
|
|
Aferir = sensor?.Aferir ?? false,
|
|
Mandatorio = sensor?.Mandatorio ?? false,
|
|
Inicializado = sensor?.Inicializado ?? false,
|
|
Liberado = sensor?.Liberado ?? false,
|
|
|
|
UltimaLeitura = ultimaLeitura,
|
|
IdadeUltimaLeituraMs = IdadeMs(ultimaLeitura),
|
|
|
|
Leituras = CriarLeituras(sensor?.ValoresLeituras)
|
|
};
|
|
}
|
|
|
|
SensoriamentoSinaleiroLogModel CriarSinaleiro(SensorSinaleiroModel sinaleiro)
|
|
{
|
|
var ultimaLeitura = sinaleiro?.UltimaLeitura ?? DateTime.MinValue;
|
|
var comportamento = sinaleiro?.Comportamento;
|
|
|
|
int statusDesejadoId = comportamento?.id ?? 0;
|
|
var statusDesejado = comportamento?.statusLED ?? StatusLED.Apagado;
|
|
|
|
int statusLidoId = sinaleiro?._StatusLedId ?? 99;
|
|
var statusLido = sinaleiro?._StatusLed ?? StatusLED.Apagado;
|
|
|
|
bool divergente =
|
|
sinaleiro?.Controlar == true &&
|
|
(statusDesejadoId != statusLidoId || statusDesejado != statusLido);
|
|
|
|
return new SensoriamentoSinaleiroLogModel
|
|
{
|
|
ID = sinaleiro?.ID,
|
|
ID_Num = sinaleiro?.ID_Num ?? 0,
|
|
Descricao = sinaleiro?.Descricao,
|
|
Componente = sinaleiro?.Componente ?? default(S_Code),
|
|
|
|
Controlar = sinaleiro?.Controlar ?? false,
|
|
Mandatorio = sinaleiro?.Mandatorio ?? false,
|
|
Inicializado = sinaleiro?.Inicializado ?? false,
|
|
|
|
StatusLedIdLeitura = statusLidoId,
|
|
StatusLedLeitura = statusLido,
|
|
|
|
StatusLedIdDesejado = statusDesejadoId,
|
|
StatusLedDesejado = statusDesejado,
|
|
StatusOperacaoDesejado = comportamento?.statusOperacao,
|
|
|
|
QtdPiscadasDesejado = comportamento?.QtdPiscadas ?? 0,
|
|
TempoMsDesejado = comportamento?.TempoMs ?? 0,
|
|
PausaMsDesejado = comportamento?.PausaMs ?? 0,
|
|
|
|
Divergente = divergente,
|
|
|
|
UltimaLeitura = ultimaLeitura,
|
|
UltimoComandoEnviado = sinaleiro?.UltimoComandoEnviado ?? DateTime.MinValue,
|
|
IdadeUltimaLeituraMs = IdadeMs(ultimaLeitura),
|
|
|
|
Leituras = CriarLeituras(sinaleiro?.ValoresLeituras)
|
|
};
|
|
}
|
|
|
|
SensoriamentoReleLogModel CriarRele(SensorReleModel rele)
|
|
{
|
|
var ultimaLeitura = rele?.UltimaLeitura ?? DateTime.MinValue;
|
|
|
|
var estadoControle = rele?.StatusControle ?? Estado.Desligado;
|
|
var estadoLeitura = rele?._EstadoLeitura ?? Estado.Desligado;
|
|
|
|
bool divergente =
|
|
rele?.Controlar == true &&
|
|
estadoControle != estadoLeitura;
|
|
|
|
return new SensoriamentoReleLogModel
|
|
{
|
|
ID = rele?.ID,
|
|
ID_Num = rele?.ID_Num ?? 0,
|
|
Descricao = rele?.Descricao,
|
|
Componente = rele?.Componente ?? default(S_Code),
|
|
|
|
Controlar = rele?.Controlar ?? false,
|
|
Mandatorio = rele?.Mandatorio ?? false,
|
|
Inicializado = rele?.Inicializado ?? false,
|
|
Liberado = rele?.Liberado ?? false,
|
|
|
|
AtuacaoNivelAlto = rele?.AtuacaoNivelAlto ?? false,
|
|
|
|
EstadoControle = estadoControle,
|
|
EstadoLeitura = estadoLeitura,
|
|
UltimoEstadoDesejado = rele?.UltimoEstadoDesejado ?? Estado.Desligado,
|
|
|
|
Divergente = divergente,
|
|
|
|
UltimaLeitura = ultimaLeitura,
|
|
UltimoComandoEnviado = rele?.UltimoComandoEnviado ?? DateTime.MinValue,
|
|
IdadeUltimaLeituraMs = IdadeMs(ultimaLeitura),
|
|
|
|
Leituras = CriarLeituras(rele?.ValoresLeituras)
|
|
};
|
|
}
|
|
|
|
SensoriamentoServoLogModel CriarServo(SensorServoModel servo)
|
|
{
|
|
var ultimaLeitura = servo?.UltimaLeitura ?? DateTime.MinValue;
|
|
|
|
int anguloControle = servo?._AnguloControle ?? -1;
|
|
int anguloLeitura = servo?._AnguloLeiutra ?? -1;
|
|
|
|
double erro = anguloControle - anguloLeitura;
|
|
|
|
bool divergente =
|
|
servo?.Controlar == true &&
|
|
anguloLeitura >= 0 &&
|
|
Math.Abs(erro) > 2.0;
|
|
|
|
return new SensoriamentoServoLogModel
|
|
{
|
|
ID = servo?.ID,
|
|
ID_Num = servo?.ID_Num ?? 0,
|
|
Descricao = servo?.Descricao,
|
|
Componente = servo?.Componente ?? default(S_Code),
|
|
|
|
Controlar = servo?.Controlar ?? false,
|
|
Mandatorio = servo?.Mandatorio ?? false,
|
|
Inicializado = servo?.Inicializado ?? false,
|
|
Liberado = servo?.Liberado ?? false,
|
|
Incremental = servo?.Incremental ?? false,
|
|
|
|
AnguloNeutro = servo?.AnguloNeutro ?? 0,
|
|
AnguloControle = anguloControle,
|
|
AnguloLeitura = anguloLeitura,
|
|
UltimoAnguloDesejado = servo?.UltimoAnguloDesejado ?? 0,
|
|
|
|
ErroAngulo = Math.Round(erro, 2),
|
|
ErroAnguloAbs = Math.Round(Math.Abs(erro), 2),
|
|
Divergente = divergente,
|
|
|
|
UltimaLeitura = ultimaLeitura,
|
|
UltimoComandoEnviado = servo?.UltimoComandoEnviado ?? DateTime.MinValue,
|
|
IdadeUltimaLeituraMs = IdadeMs(ultimaLeitura),
|
|
|
|
Leituras = CriarLeituras(servo?.ValoresLeituras)
|
|
};
|
|
}
|
|
|
|
List<SensoriamentoLeituraLogModel> CriarLeituras(List<SensorValoresLeituraModel> leituras)
|
|
{
|
|
return (leituras ?? new List<SensorValoresLeituraModel>())
|
|
.Select(x => CriarLeitura(x))
|
|
.ToList();
|
|
}
|
|
|
|
SensoriamentoLeituraLogModel CriarLeitura(SensorValoresLeituraModel _leitura)
|
|
{
|
|
object valor = _leitura?.atual?.valor;
|
|
DateTime lidoEm = _leitura?.atual?.lidoEm ?? DateTime.MinValue;
|
|
|
|
double? valorNumerico = ConverterParaDouble(valor);
|
|
bool? valorBool = ConverterParaBool(valor);
|
|
|
|
bool? dentroFaixa = null;
|
|
|
|
if (_leitura?.analise_health == true)
|
|
{
|
|
if (valorNumerico.HasValue)
|
|
{
|
|
bool temFaixaConfigurada = _leitura.minimo != 0 || _leitura.maximo != 0;
|
|
|
|
dentroFaixa = !temFaixaConfigurada ||
|
|
(valorNumerico.Value >= _leitura.minimo &&
|
|
valorNumerico.Value <= _leitura.maximo);
|
|
}
|
|
else if (valorBool.HasValue)
|
|
{
|
|
dentroFaixa = valorBool.Value;
|
|
}
|
|
else
|
|
{
|
|
dentroFaixa = false;
|
|
}
|
|
}
|
|
|
|
return new SensoriamentoLeituraLogModel
|
|
{
|
|
Funcao = _leitura?.funcao ?? default(FuncoesPinout),
|
|
Posicao = _leitura?.posicao ?? default(CanMessagePosicaoDados),
|
|
Indice = _leitura?.indice ?? 0,
|
|
|
|
Valor = valor,
|
|
ValorTexto = valor?.ToString(),
|
|
ValorNumerico = valorNumerico,
|
|
ValorBool = valorBool,
|
|
|
|
UnidadeMedida = _leitura?.unidade_medida,
|
|
|
|
AnaliseHealth = _leitura?.analise_health ?? false,
|
|
Minimo = _leitura?.minimo ?? 0,
|
|
Maximo = _leitura?.maximo ?? 0,
|
|
Nominal = _leitura?.nominal ?? 0,
|
|
|
|
DentroFaixa = dentroFaixa,
|
|
|
|
LidoEm = lidoEm,
|
|
IdadeMs = IdadeMs(lidoEm)
|
|
};
|
|
}
|
|
|
|
List<string> CriarAlertas(SensoriamentoLogModel _model)
|
|
{
|
|
var alertas = new List<string>();
|
|
|
|
if (!_model.Disponivel)
|
|
alertas.Add("Sensoriamento indisponível.");
|
|
|
|
if (!_model.Conectado)
|
|
alertas.Add("Módulo SEN desconectado ou sem resposta dentro do timeout.");
|
|
|
|
if (!_model.ConexaoAtivaHealth)
|
|
alertas.Add("HealthWorker não considera SEN operante.");
|
|
|
|
foreach (var sensor in _model.Sensores.Where(x => x.Mandatorio && !x.Liberado))
|
|
alertas.Add($"Sensor mandatório não liberado: {sensor.ID}.");
|
|
|
|
foreach (var sensor in _model.Sensores)
|
|
{
|
|
foreach (var _leitura in sensor.Leituras.Where(x => x.DentroFaixa == false))
|
|
{
|
|
alertas.Add(
|
|
$"Leitura fora da faixa: {sensor.ID}.{_leitura.Funcao} = {_leitura.ValorTexto} {_leitura.UnidadeMedida}"
|
|
);
|
|
}
|
|
}
|
|
|
|
foreach (var rele in _model.Reles.Where(x => x.Divergente))
|
|
alertas.Add($"Relé divergente: {rele.ID}. Controle={rele.EstadoControle}, Leitura={rele.EstadoLeitura}.");
|
|
|
|
foreach (var servo in _model.Servos.Where(x => x.Divergente))
|
|
alertas.Add($"Servo divergente: {servo.ID}. Controle={servo.AnguloControle}, Leitura={servo.AnguloLeitura}.");
|
|
|
|
foreach (var sinaleiro in _model.Sinaleiros.Where(x => x.Divergente))
|
|
alertas.Add($"Sinaleiro divergente: {sinaleiro.ID}. Desejado={sinaleiro.StatusLedDesejado}, Leitura={sinaleiro.StatusLedLeitura}.");
|
|
|
|
return alertas;
|
|
}
|
|
|
|
double IdadeMs(DateTime momento)
|
|
{
|
|
if (momento == DateTime.MinValue)
|
|
return -1;
|
|
|
|
return Math.Round((agora - momento).TotalMilliseconds, 2);
|
|
}
|
|
|
|
double? ConverterParaDouble(object valor)
|
|
{
|
|
if (valor == null)
|
|
return null;
|
|
|
|
try
|
|
{
|
|
if (valor is double d) return d;
|
|
if (valor is float f) return f;
|
|
if (valor is int i) return i;
|
|
if (valor is long l) return l;
|
|
if (valor is decimal m) return (double)m;
|
|
if (valor is byte b) return b;
|
|
if (valor is short s) return s;
|
|
|
|
if (double.TryParse(
|
|
valor.ToString()?.Replace(",", "."),
|
|
NumberStyles.Any,
|
|
CultureInfo.InvariantCulture,
|
|
out double result))
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
bool? ConverterParaBool(object valor)
|
|
{
|
|
if (valor == null)
|
|
return null;
|
|
|
|
if (valor is bool b)
|
|
return b;
|
|
|
|
if (valor is int i)
|
|
return i != 0;
|
|
|
|
if (valor is byte by)
|
|
return by != 0;
|
|
|
|
if (bool.TryParse(valor.ToString(), out bool result))
|
|
return result;
|
|
|
|
return null;
|
|
}
|
|
|
|
var dados = op.DispSen?.Dados;
|
|
var leitura = dados?.DadosLeitura;
|
|
|
|
var model = new SensoriamentoLogModel();
|
|
|
|
model.Momento = agora;
|
|
model.Disponivel = dados != null;
|
|
|
|
if (dados == null)
|
|
{
|
|
model.Conectado = false;
|
|
model.ConexaoAtivaHealth = false;
|
|
model.Dispositivo = T_Code.Sen;
|
|
model.Mod_ID = "";
|
|
model.Alertas = new List<string> { "DispSen/Dados indisponível" };
|
|
model.Sensores = new List<SensoriamentoSensorLogModel>();
|
|
model.Sinaleiros = new List<SensoriamentoSinaleiroLogModel>();
|
|
model.Reles = new List<SensoriamentoReleLogModel>();
|
|
model.Servos = new List<SensoriamentoServoLogModel>();
|
|
|
|
Sensoriamento = model;
|
|
return;
|
|
}
|
|
|
|
model.Conectado = dados.Conectado;
|
|
model.ConexaoAtivaHealth = dados.ConexaoAtiva;
|
|
|
|
model.Dispositivo = leitura?.Dispositivo ?? dados.Dispositivo;
|
|
model.Versao = leitura?.Versao ?? 0;
|
|
model.Mod_ID = leitura?.Mod_ID ?? dados.Modulo_ID;
|
|
|
|
model.EnderecoCanTx = dados._EnderecoCAN_Tx;
|
|
model.EnderecoCanRx = dados._EnderecoCAN_Rx;
|
|
|
|
model.TaxaAmostragemMs = dados._TaxaAmostragem;
|
|
model.FrequenciaBaseHz = dados.FrequenciaBase;
|
|
model.RequisitarDados = dados.RequisitarDados;
|
|
|
|
model.LatenciaLoopMs = leitura?.LatenciaLoop ?? 0;
|
|
|
|
model.UltimoComandoRespondido = leitura?.UltimoComandoRespondido ?? DateTime.MinValue;
|
|
model.IdadeUltimoComandoMs = IdadeMs(model.UltimoComandoRespondido);
|
|
|
|
model.Sensores = (dados.Sensores ?? new List<SensorModel>())
|
|
.Select(x => CriarSensor(x))
|
|
.ToList();
|
|
|
|
model.Sinaleiros = (dados.Sinaleiros ?? new List<SensorSinaleiroModel>())
|
|
.Select(x => CriarSinaleiro(x))
|
|
.ToList();
|
|
|
|
model.Reles = (dados.Reles ?? new List<SensorReleModel>())
|
|
.Select(x => CriarRele(x))
|
|
.ToList();
|
|
|
|
model.Servos = (dados.Servos ?? new List<SensorServoModel>())
|
|
.Select(x => CriarServo(x))
|
|
.ToList();
|
|
|
|
AtualizarResumo(model);
|
|
model.Alertas = CriarAlertas(model);
|
|
|
|
Sensoriamento = model;
|
|
}
|
|
|
|
// Mov
|
|
public MovimentacaoLogModel Movimentacao { get; set; } = new MovimentacaoLogModel();
|
|
public void AtualizarMovimentacao(DateTime agora)
|
|
{
|
|
if (op == null) return;
|
|
|
|
MovimentacaoModuloLogModel CriarModuloAtualizado(ModuloMvdModel modulo)
|
|
{
|
|
var mov = modulo?.MovMotor;
|
|
var freio = mov?.ConfigFreio;
|
|
var leitura = mov?.Leitura;
|
|
|
|
string moduloId = modulo?.Modulo_ID ?? mov?.Mod_ID ?? "";
|
|
|
|
return new MovimentacaoModuloLogModel
|
|
{
|
|
Modulo_ID = moduloId,
|
|
|
|
EnderecoCanTx = mov?._EnderecoCAN_Tx ?? 0,
|
|
EnderecoCanRx = mov?._EnderecoCAN_Rx ?? 0,
|
|
|
|
Inicializado = mov?.Inicializado ?? false,
|
|
Comandar = mov?.Comandar ?? false,
|
|
AtivadoLeitura = mov?.LeituraLigado ?? false,
|
|
AtivadoComando = mov?.ComandoLigado ?? false,
|
|
|
|
RPM_SP = mov?.RPM_SP ?? 0,
|
|
RPM_SP_Controle = mov?.RPM_SP_Controle ?? 0,
|
|
RPM_SP_RodaEstimado = mov?.RPM_SP_Leitura ?? 0,
|
|
|
|
RPM_Motor = mov?.RPM_Motor ?? 0,
|
|
RPM_Roda = mov?.RPM_Roda ?? 0,
|
|
VelocidadeInstantaneaMs = mov?.VelocidadeInstantanea ?? 0,
|
|
|
|
Sentido_SP = mov?.Sentido_SP ?? Sentido.Parado,
|
|
SentidoLeitura = mov?.Sentido ?? Sentido.Parado,
|
|
|
|
Tensao = mov?.Tensao ?? 0,
|
|
CorrenteMotor = mov?.Corrente_Motor ?? 0,
|
|
CorrenteBarramento = mov?.Corrente_Barramento ?? 0,
|
|
Potencia = mov?.Potencia ?? 0,
|
|
CicloTrabalho = mov?.CicloTrabalho ?? 0,
|
|
|
|
TemperaturaMotor = mov?.Temperatura ?? 0,
|
|
TemperaturaDriver = mov?.TemperaturaDriver ?? 0,
|
|
|
|
CodigoAlarme = mov?.CodigoAlarme ?? OidCodigoErro.NenhumErro,
|
|
AlarmeMotor = mov?.AlarmeMotor ?? false,
|
|
AlarmeSensores = mov?.AlarmeSensores ?? false,
|
|
AlarmeComando = mov?.AlarmeComando ?? false,
|
|
|
|
FreadoLeituraOid = leitura?.Freado ?? false,
|
|
FreioSP = mov?.UltimoFreioSP ?? false,
|
|
FreioServoLeitura = freio?.Leitura ?? false,
|
|
FreioServoAnguloControle = freio?.AnguloControle ?? -1,
|
|
FreioServoComandoPendente = freio?.EnviarComando ?? false,
|
|
FreioServoUltimoEnvio = freio?.UltimoEnvio ?? DateTime.MinValue,
|
|
|
|
UltimoComandoEnviado = mov?.UltimoComandoEnviado ?? DateTime.MinValue,
|
|
UltimoComandoRespondido = leitura?.UltimoComandoRecebido ?? DateTime.MinValue,
|
|
UltimoModoControleEnviado = mov?.UltimoModoControleEnviado ?? default,
|
|
UltimoSetPointEnviado = mov?.UltimoSetPointEnviado ?? 0,
|
|
UltimaDirecao = mov?.UltimaDirecao ?? Direcao.Parado,
|
|
|
|
FatorCompensacaoCurva = BuscarFatorCompensacao(moduloId)
|
|
};
|
|
}
|
|
|
|
MovimentacaoStatusLadoLogModel CriarStatus((bool, List<string>) status)
|
|
{
|
|
return new MovimentacaoStatusLadoLogModel
|
|
{
|
|
Ok = status.Item1,
|
|
Motivos = status.Item2 ?? new List<string>()
|
|
};
|
|
}
|
|
|
|
MovimentacaoStatusLadoLogModel CriarStatusIndisponivel(string motivo)
|
|
{
|
|
return new MovimentacaoStatusLadoLogModel
|
|
{
|
|
Ok = false,
|
|
Motivos = new List<string> { motivo }
|
|
};
|
|
}
|
|
|
|
double MediaOuZero<T>(IEnumerable<T> origem, Func<T, double> seletor)
|
|
{
|
|
var lista = origem?.ToList() ?? new List<T>();
|
|
|
|
if (lista.Count == 0)
|
|
return 0;
|
|
|
|
var valores = lista
|
|
.Select(seletor)
|
|
.Where(x => !double.IsNaN(x) && !double.IsInfinity(x))
|
|
.ToList();
|
|
|
|
return valores.Count == 0 ? 0 : valores.Average();
|
|
}
|
|
|
|
double BuscarFatorCompensacao(string moduloId)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(moduloId))
|
|
return 1.0;
|
|
|
|
if (MovimentacaoMovimentoCompensadoModel.compensacoes != null && MovimentacaoMovimentoCompensadoModel.compensacoes.TryGetValue(moduloId, out var fator))
|
|
{
|
|
return fator;
|
|
}
|
|
|
|
return 1.0;
|
|
}
|
|
|
|
var dados = op.DispMvd?.Dados;
|
|
|
|
var modulos = dados?.Modulos?
|
|
.Where(x => x?.MovMotor != null)
|
|
.ToList() ?? new List<ModuloMvdModel>();
|
|
|
|
var modulosInicializados = modulos
|
|
.Where(x => x.MovMotor.Inicializado)
|
|
.ToList();
|
|
|
|
MovimentacaoLogModel model = new MovimentacaoLogModel();
|
|
|
|
model.Momento = agora;
|
|
model.Disponivel = dados != null;
|
|
model.TotalModulos = modulos.Count;
|
|
model.ModulosInicializados = modulosInicializados.Count;
|
|
|
|
model.VelocidadeMediaMs = dados?.VelocidadeMedia ?? 0;
|
|
model.TempoMovimentoSegs = dados?.TempoEmAtividade ?? 0;
|
|
model.DistanciaPercorridaTotal = dados?.DistanciaPercorridaTotal ?? 0;
|
|
model.DistanciaPercorridaParcial = dados?.DistanciaPercorridaParcial ?? 0;
|
|
|
|
model.RPMRodaMedio = MediaOuZero(modulosInicializados, x => x.MovMotor.RPM_Roda);
|
|
model.RPMMotorMedio = MediaOuZero(modulosInicializados, x => x.MovMotor.RPM_Motor);
|
|
model.TemperaturaMotorMedia = MediaOuZero(modulosInicializados, x => x.MovMotor.Temperatura);
|
|
model.TemperaturaDriverMedia = MediaOuZero(modulosInicializados, x => x.MovMotor.TemperaturaDriver);
|
|
|
|
model.EsqStatus = dados != null
|
|
? CriarStatus(dados.StatusModulosMOV(Direcao.Esquerda))
|
|
: CriarStatusIndisponivel("DispMvd/Dados indisponível");
|
|
|
|
model.DirStatus = dados != null
|
|
? CriarStatus(dados.StatusModulosMOV(Direcao.Direita))
|
|
: CriarStatusIndisponivel("DispMvd/Dados indisponível");
|
|
|
|
model.Modulos = modulos
|
|
.Select(CriarModuloAtualizado)
|
|
.ToList();
|
|
|
|
Movimentacao = model;
|
|
}
|
|
|
|
// Dir
|
|
public DirecionalLogModel Direcional { get; set; } = new DirecionalLogModel();
|
|
public void AtualizarDirecional(DateTime agora)
|
|
{
|
|
if (op == null) return;
|
|
|
|
DirecionalModuloLogModel CriarModuloAtualizado(ModuloMvdModel modulo)
|
|
{
|
|
var dir = modulo?.DirMotor;
|
|
var leitura = dir?.Leitura;
|
|
var sensorAngulo = dir?.SensorAnguloReal;
|
|
|
|
string moduloId = modulo?.Modulo_ID ?? dir?.Mod_ID ?? "";
|
|
|
|
double velocidadeMax = dir?.Velocidade_Max ?? 0;
|
|
int velocidade = dir?.Velocidade ?? 0;
|
|
|
|
double velocidadePercentual =
|
|
velocidadeMax > 0
|
|
? (velocidade / velocidadeMax) * 100.0
|
|
: 0;
|
|
|
|
double erroAngulo = dir != null ? CalcularErroAngulo(dir) : 0;
|
|
|
|
return new DirecionalModuloLogModel
|
|
{
|
|
Modulo_ID = moduloId,
|
|
|
|
EnderecoCanTx = dir?._EnderecoCAN_Tx ?? 0,
|
|
EnderecoCanRx = dir?._EnderecoCAN_Rx ?? 0,
|
|
|
|
Inicializado = dir?.Inicializado ?? false,
|
|
Controlar = dir?.Comandar ?? false,
|
|
|
|
Angulo_SP = dir?.Angulo_SP ?? 0,
|
|
Sentido_SP = dir?.Sentido_SP ?? Sentido.Parado,
|
|
UltimaDirecao = dir?.UltimaDirecao ?? Direcao.Parado,
|
|
|
|
Velocidade = velocidade,
|
|
VelocidadePercentual = Math.Round(velocidadePercentual, 2),
|
|
VelocidadeMax = velocidadeMax,
|
|
|
|
AnguloDriver = dir?.AnguloDriver ?? 0,
|
|
AnguloReal = dir?.AnguloReal ?? double.NaN,
|
|
AnguloLeitura = dir?.AnguloLeitura ?? 0,
|
|
|
|
UsarAnguloSensor = dir?.UsarAnguloSensor ?? false,
|
|
SensorAnguloRealInicializado = sensorAngulo?.Inicializado ?? false,
|
|
SensorAnguloRealAferir = sensorAngulo?.Aferir ?? false,
|
|
|
|
ErroAngulo = Math.Round(erroAngulo, 2),
|
|
ErroAnguloAbs = Math.Round(Math.Abs(erroAngulo), 2),
|
|
AtingiuAnguloSP = dir?.AtingiuAnguloSP ?? false,
|
|
RetornandoAzero = dir?.RetornandoAzero ?? false,
|
|
|
|
SentidoLeitura = dir?.Sentido ?? Sentido.Parado,
|
|
SentidoReal = dir?.SentidoReal ?? Sentido.Parado,
|
|
RPM = dir?.RPM ?? 0,
|
|
EmMovimento = dir?.EmMovimento ?? false,
|
|
|
|
FolgaMecanica = dir?.FolgaMecanica ?? 0,
|
|
AnguloFolgaCompensar = dir?.AnguloFolgaCompensar ?? 0,
|
|
OffsetAnguloReal = dir?.OffsetAnguloReal ?? 0,
|
|
|
|
IN1_Atuado = dir?.IN1_Atuado ?? false,
|
|
IN2_Atuado = dir?.IN2_Atuado ?? false,
|
|
|
|
Referenciando = dir?.Referenciando ?? false,
|
|
Referenciado = dir?.Referenciado ?? false,
|
|
UltimoReferenciamento = dir?.UltimoReferenciamento ?? DateTime.MinValue,
|
|
|
|
UltimoComandoEnviado = dir?.UltimoComandoEnviado ?? DateTime.MinValue,
|
|
UltimoComandoRespondido = leitura?.UltimoComandoRecebido ?? DateTime.MinValue
|
|
};
|
|
}
|
|
|
|
double CalcularErroAngulo(DirecionalModel dir)
|
|
{
|
|
if (dir == null)
|
|
return 0;
|
|
|
|
double anguloSp =
|
|
!dir.Comandar || dir.Sentido_SP == Sentido.Parado
|
|
? 0
|
|
: dir.Angulo_SP;
|
|
|
|
return anguloSp - dir.AnguloLeitura;
|
|
}
|
|
|
|
DirecionalStatusLogModel CriarStatus((bool, List<string>) status)
|
|
{
|
|
return new DirecionalStatusLogModel
|
|
{
|
|
Ok = status.Item1,
|
|
Motivos = status.Item2 ?? new List<string>()
|
|
};
|
|
}
|
|
|
|
DirecionalStatusLogModel CriarStatusIndisponivel(string motivo)
|
|
{
|
|
return new DirecionalStatusLogModel
|
|
{
|
|
Ok = false,
|
|
Motivos = new List<string> { motivo }
|
|
};
|
|
}
|
|
|
|
double MediaOuZero<T>(IEnumerable<T> origem, Func<T, double> seletor)
|
|
{
|
|
var lista = origem?.ToList() ?? new List<T>();
|
|
|
|
if (lista.Count == 0)
|
|
return 0;
|
|
|
|
var valores = lista
|
|
.Select(seletor)
|
|
.Where(x => !double.IsNaN(x) && !double.IsInfinity(x))
|
|
.ToList();
|
|
|
|
return valores.Count == 0 ? 0 : valores.Average();
|
|
}
|
|
|
|
var dados = op.DispMvd?.Dados;
|
|
var controle = op.Controle;
|
|
|
|
var modulos = dados?.Modulos?
|
|
.Where(x => x?.DirMotor != null)
|
|
.ToList() ?? new List<ModuloMvdModel>();
|
|
|
|
var inicializados = modulos
|
|
.Where(x => x.DirMotor.Inicializado)
|
|
.ToList();
|
|
|
|
var controlando = modulos
|
|
.Where(x => x.DirMotor.Inicializado && x.DirMotor.Comandar)
|
|
.ToList();
|
|
|
|
DirecionalLogModel model = new DirecionalLogModel();
|
|
|
|
model.Momento = agora;
|
|
model.Disponivel = dados != null;
|
|
model.TotalModulos = modulos.Count;
|
|
model.ModulosInicializados = inicializados.Count;
|
|
model.ModulosControlando = controlando.Count;
|
|
|
|
model.TipoMovimento = controle?.TipoMovimento ?? default;
|
|
|
|
model.UltimaDirecaoControle =
|
|
controle?.TiposControle?
|
|
.FirstOrDefault(x => x.Tipo == T_Code.Dir)?
|
|
.UltimaDirecao ?? Direcao.Parado;
|
|
|
|
model.AnguloMedioAbs = MediaOuZero(controlando, x => Math.Abs(x.DirMotor.AnguloLeitura));
|
|
model.AnguloSPMedioAbs = MediaOuZero(controlando, x => Math.Abs(x.DirMotor.Angulo_SP));
|
|
model.ErroAnguloMedioAbs = MediaOuZero(controlando, x => Math.Abs(CalcularErroAngulo(x.DirMotor)));
|
|
|
|
model.Status =
|
|
dados != null && controle != null
|
|
? CriarStatus(dados.StatusModulosDIR(controle.TipoMovimento))
|
|
: CriarStatusIndisponivel("DispMvd/Dados ou Controle indisponível");
|
|
|
|
model.Modulos = modulos
|
|
.Select(CriarModuloAtualizado)
|
|
.ToList();
|
|
|
|
Direcional = model;
|
|
}
|
|
|
|
// Imu
|
|
public ModuloIMUModel IMU { get; set; } = new ModuloIMUModel();
|
|
public void AtualizarImu(DateTime agora)
|
|
{
|
|
if (op == null) return;
|
|
|
|
try
|
|
{
|
|
string imu = RedisService.Get(RedisService.ModKey(T_Code.Imu)) ?? "";
|
|
var sIMU = JsonConvert.DeserializeObject<ModuloIMUModel>(imu) ?? new ModuloIMUModel();
|
|
|
|
sIMU.Momento = agora;
|
|
IMU = sIMU;
|
|
}
|
|
catch
|
|
{
|
|
IMU = new ModuloIMUModel()
|
|
{
|
|
Momento = agora
|
|
};
|
|
}
|
|
}
|
|
|
|
// Gps
|
|
public GPSModel Gps { get; set; } = new GPSModel();
|
|
public void AtualizarGps(DateTime agora)
|
|
{
|
|
if (op == null) return;
|
|
|
|
Gps = GPSService.GetSnapshot() ?? new GPSModel();
|
|
Gps.Momento = agora;
|
|
|
|
if (VariaveisOperacao.PosicaoBase != null)
|
|
VariaveisOperacao.PosicaoBase.Momento = agora;
|
|
}
|
|
|
|
// Lvx
|
|
public LivoxModel LivoxLidar { get; set; } = new LivoxModel();
|
|
public void AtualizarLivox(DateTime agora)
|
|
{
|
|
if (op == null) return;
|
|
|
|
LivoxLidar = LivoxManagerProcess.DadosLeitura?.Clone() ?? new LivoxModel();
|
|
LivoxLidar.Momento = agora;
|
|
}
|
|
|
|
// Bat
|
|
public OperacaoSensoriamentoLogBateriaModel Bateria { get; set; } = new OperacaoSensoriamentoLogBateriaModel();
|
|
public void AtualizarBateria(DateTime agora)
|
|
{
|
|
if (op == null) return;
|
|
|
|
var _dispSen = op.DispSen?.Dados;
|
|
var _Bateria = _dispSen?.ContadorCarga;
|
|
|
|
if (_Bateria == null)
|
|
{
|
|
Bateria = new OperacaoSensoriamentoLogBateriaModel()
|
|
{
|
|
Momento = agora,
|
|
Iniciado = false,
|
|
BmsLigado = false,
|
|
};
|
|
return;
|
|
}
|
|
|
|
Bateria = new OperacaoSensoriamentoLogBateriaModel()
|
|
{
|
|
Momento = agora,
|
|
Iniciado = _Bateria.Iniciado,
|
|
BmsLigado = _Bateria.BmsLigado,
|
|
_dt = _Bateria._dt,
|
|
PercentualBateria = _Bateria.PercentualBateria,
|
|
PercentualBateriaConsumida = _Bateria.PercentualConsumidoTotal,
|
|
PercentualBateriaConsumidaOperacao = _Bateria.PercentualConsumidoOperacao,
|
|
TempoEstimadoRestanteMinutos = _Bateria.TempoEstimadoMinutos,
|
|
CorrenteInstantanea = _Bateria.CorrenteInstantanea,
|
|
TensaoInstantanea = _Bateria.TensaoInstantanea,
|
|
PotenciaInstantanea = _Bateria.PotenciaInstantanea,
|
|
WhPorMetro = _Bateria.WhPorMetro,
|
|
DistanciaEstimadaRestanteMetros = _Bateria.DistanciaEstimadaRestante_m,
|
|
Temperatura = _Bateria.Temperatura,
|
|
Barramentos = _dispSen?.Sensores?.Where(x => x.Componente == S_Code.sCOR)?.Select(x => new OperacaoSensoriamentoLogBateriaBarramentoModel()
|
|
{
|
|
ID = x.ID,
|
|
Iniciado = x.Inicializado,
|
|
Descricao = x.Descricao,
|
|
Tensao = x.ValoresLeituras?.FirstOrDefault(y => y.funcao == FuncoesPinout.Tensao)?.atual?.valor ?? -1,
|
|
Corrente = x.ValoresLeituras?.FirstOrDefault(y => y.funcao == FuncoesPinout.Corrente)?.atual?.valor ?? -1,
|
|
Potencia = x.ValoresLeituras?.FirstOrDefault(y => y.funcao == FuncoesPinout.Potencia)?.atual?.valor ?? -1,
|
|
Energia = x.ValoresLeituras?.FirstOrDefault(y => y.funcao == FuncoesPinout.Energia)?.atual?.valor ?? -1,
|
|
Temperatura = x.ValoresLeituras?.FirstOrDefault(y => y.funcao == FuncoesPinout.Temperatura)?.atual?.valor ?? -1,
|
|
}).ToList()
|
|
};
|
|
}
|
|
|
|
// Trj
|
|
public OperacaoSensoriamentoLogTrajetoriaModel Trajetoria { get; set; }
|
|
public void AtualizarTrajetoria(DateTime agora)
|
|
{
|
|
if (op == null) return;
|
|
|
|
var _Trajetoria = op.Trajetoria;
|
|
Trajetoria = new OperacaoSensoriamentoLogTrajetoriaModel()
|
|
{
|
|
Momento = agora,
|
|
StatusCarro = _Trajetoria?.StatusAtual ?? StatusCarroMapa.Parado,
|
|
TrajetoriaConcluida = _Trajetoria?.TrajeotiraConcluida ?? false,
|
|
DistanciaDireita = _Trajetoria?.DistanciaDireita ?? 0,
|
|
DistanciaEsquerda = _Trajetoria?.DistanciaEsquerda ?? 0,
|
|
ProgressoTrajeto = FuncoesMatematicas.Clamp(_Trajetoria?.PercentualTrajetoria ?? 0, 0, 100),
|
|
CorredorAtual = _Trajetoria?.CorredorAtual?.Clone(false) ?? new CorredorTrajetoriaModel(),
|
|
DirecaoCaminho = _Trajetoria?.DirecaoCaminho ?? DirecaoCarroRua.Parado,
|
|
AnguloCaminho = _Trajetoria?.AnguloCaminho ?? 0,
|
|
AnguloMedioCorredor = _Trajetoria?.AnguloMedioCorredor ?? 0,
|
|
DistanciaTotal = _Trajetoria?.DistanciaTotal ?? 0,
|
|
DistanciaPercorrida = _Trajetoria?.DistanciaPercorrida ?? 0,
|
|
DistanciaRestante = _Trajetoria?.DistanciaRestante ?? 0,
|
|
NaMargemDoCorredor = _Trajetoria?.NaMargemDoCorredor ?? false,
|
|
ManobrandoEntreRuas = _Trajetoria?.ManobrandoEntreRuas ?? false,
|
|
TempoEstimadoRestante = _Trajetoria?.TempoEstimadoRestante ?? "",
|
|
TempoEstimadoOperacao = _Trajetoria?.TempoEstimadoOperacao ?? "",
|
|
ProximoPonto = _Trajetoria?.ProximoPonto?.Clone() ?? new PontoTrajetoriaModel(TipoPontoRua.PosicaoRobo),
|
|
PontoMaisProximo = _Trajetoria?.PontoMaisProximo?.Clone() ?? new PontoTrajetoriaModel(TipoPontoRua.PosicaoRobo),
|
|
PontoAtual = _Trajetoria?.PontoAtual?.Clone() ?? new PontoTrajetoriaModel(TipoPontoRua.PosicaoRobo),
|
|
ErroLateralAngular = _Trajetoria?.ErroLateralAngular ?? 0,
|
|
ErroOrientacaoAngular = _Trajetoria?.ErroOrientacaoAngular ?? 0,
|
|
ErroOrientacaoAngularCombinado = _Trajetoria?.ErroOrientacaoAngularCombinado ?? 0,
|
|
ErroOrientacaoAngularCaminho = _Trajetoria?.ErroOrientacaoAngularCaminho ?? 0,
|
|
ErroOrientacaoAngularProximoPonto = _Trajetoria?.ErroOrientacaoAngularProximoPonto ?? 0,
|
|
PercentualOperacao = _Trajetoria?.PercentualTrajetoria ?? 0,
|
|
PercentualRuaAtual = _Trajetoria?.CorredorAtual?.Progresso ?? 0,
|
|
IdxRuaAtual = _Trajetoria?.CorredorAtual?.Idx ?? 0,
|
|
QtdPontos = _Trajetoria?.TrajetoriaFixa?.Count ?? 0,
|
|
DistanciaErroMapaCana = _Trajetoria?.DistanciaErroMapaPlantacao ?? 0,
|
|
PrimeiroPontoDentroMapa = _Trajetoria?.PrimeiroPontoDentroMapa?.Clone() ?? new GPSModel(),
|
|
PrimeiroPontoDentroCana = _Trajetoria?.PrimeiroPontoDentroCana?.Clone() ?? new GPSModel(),
|
|
AutonomiaCooredor = _Trajetoria?.AutonomiaCorredor?.Clone(),
|
|
};
|
|
}
|
|
|
|
// Npc
|
|
public PerformanceModel DadosPerformance { get; set; } = new PerformanceModel();
|
|
|
|
// HealthWorker
|
|
public HealthWorkerModel OperadorSaude { get; set; } = new HealthWorkerModel();
|
|
// VisualWorker
|
|
public VisualWorkerModel OperadorVisual { get; set; } = new VisualWorkerModel();
|
|
// WeedWorker
|
|
public WeedWorkerModel OperadorErvas { get; set; } = new WeedWorkerModel();
|
|
public void AtualizarOperadores(DateTime agora)
|
|
{
|
|
if (op == null) return;
|
|
|
|
HealthWorkerService.DadosLeitura.ModulosSaude = RedisService.GetField<ManagerWorkerMessageResponseModulosPendentesModel[]>(CtxKey.DadosOperacao, "status_modulos")?.ToList() ?? new List<ManagerWorkerMessageResponseModulosPendentesModel>();
|
|
OperadorSaude = HealthWorkerService.DadosLeitura.Clone();
|
|
OperadorSaude.Momento = agora;
|
|
OperadorVisual = VisualWorkerService.DadosLeitura.Clone();
|
|
OperadorVisual.Momento = agora;
|
|
OperadorErvas = WeedWorkerService.DadosLeitura.Clone();
|
|
OperadorErvas.Momento = agora;
|
|
}
|
|
// Logs
|
|
public List<OperacaoSensoriamentoLogErrosModel> Logs { get; set; } = new List<OperacaoSensoriamentoLogErrosModel>();
|
|
// CoolerControl
|
|
public CoolerControlDataModel CoolerControl { get; set; } = new CoolerControlDataModel();
|
|
|
|
public DateTime UltimoRegistroLog { get; set; } = DateTime.MinValue;
|
|
|
|
|
|
public void InserirLog(T_Code dispositivo, StatusModulo status, double saude, string mensagem, string id = null, string condicoes = null)
|
|
{
|
|
op?.InserirEventoOperacao(
|
|
dispositivo,
|
|
status,
|
|
saude,
|
|
mensagem,
|
|
id,
|
|
condicoes
|
|
);
|
|
}
|
|
|
|
|
|
public void AtualizarDados()
|
|
{
|
|
if (op == null) return;
|
|
|
|
if (Variaveis.OperacaoEmAndamento != null && !ReferenceEquals(Variaveis.OperacaoEmAndamento, op))
|
|
op = Variaveis.OperacaoEmAndamento;
|
|
|
|
DateTime agora = DateTime.Now;
|
|
|
|
// Contexto
|
|
HealthWorkerService.AtualizarDadosContexto();
|
|
VisualWorkerService.AtualizarAnalise();
|
|
WeedWorkerService.AtualizarAnalise();
|
|
CameraWorkerService.AtualizarDadosCameras();
|
|
GPSService.AtualizaDadosRedis();
|
|
LivoxManagerProcess.AtualizarLeitura();
|
|
MovimentacaoMovimentoCompensadoModel.AtualizarDados();
|
|
DalyBMSService.AtualizarDados();
|
|
SerialService.DispositivosMapeados.ForEach(d => d.AtualizarDados());
|
|
|
|
|
|
// Modulos
|
|
AtualizarOperacao(agora);
|
|
AtualizarAtuador(agora);
|
|
AtualizarSensoriamento(agora);
|
|
AtualizarMovimentacao(agora);
|
|
AtualizarDirecional(agora);
|
|
AtualizarImu(agora);
|
|
AtualizarOperadores(agora);
|
|
AtualizarBateria(agora);
|
|
AtualizarTrajetoria(agora);
|
|
AtualizarGps(agora);
|
|
AtualizarLivox(agora);
|
|
DadosPerformance.AtualizarDadosPerformance();
|
|
|
|
|
|
// Metricas
|
|
var _Trajetoria = op.Trajetoria;
|
|
_Trajetoria?.AtualizarDadosAutonomiaCorredor();
|
|
|
|
var _DispMvd = op.DispMvd;
|
|
_DispMvd?.Dados?.AtualizarDadosFreio();
|
|
|
|
var _DispAtu = op.DispAtu;
|
|
_DispAtu?.Dados?.AtualizarMetricasOperacao();
|
|
|
|
var _DispSen = op.DispSen;
|
|
_DispSen?.Dados?.AtualizarStatusSinaleiros(op.Parametros?.Modo ?? ModoOperacao.NaoDefinido, op.Sensoriamento.Operacao.StatusOperacaoAtual);
|
|
|
|
var _Bateria = _DispSen?.Dados?.ContadorCarga;
|
|
_Bateria?.AtualizarConsumo(Movimentacao.DistanciaPercorridaTotal);
|
|
|
|
var _Reservatorio = _DispAtu?.Dados?.ContadorCarga;
|
|
_Reservatorio?.AtualizarConsumo(Movimentacao.DistanciaPercorridaTotal, op.Sensoriamento.Operacao.TempoDecorridoSeg, Movimentacao.VelocidadeMediaMs);
|
|
_Reservatorio?.AtualizarAgitadorCalda(op.Parametros?.Controle?.AtuAgitadorModo ?? ModoAgitadorCalda.SemAgitacao);
|
|
|
|
var _Cooler = _DispSen?.Dados?.CoolerControl;
|
|
_Cooler?.Atualizar(Math.Max(DadosPerformance?.GPU_temp ?? 0, DadosPerformance?.CPU_temp ?? 0), agora);
|
|
|
|
|
|
// Clones
|
|
var dadosOperacao = Operacao?.Clone();
|
|
var dadosIMU = IMU?.Clone();
|
|
var dadosAtuador = Atuador?.Clone();
|
|
var dadosSensoriamento = Sensoriamento?.Clone();
|
|
var dadosMovimentacao = Movimentacao?.Clone();
|
|
var dadosDirecional = Direcional?.Clone();
|
|
var dadosBateria = Bateria?.Clone();
|
|
var dadosTrajetoria = Trajetoria?.Clone();
|
|
var dadosGps = Gps?.Clone();
|
|
var dadosPerformance = DadosPerformance?.Clone();
|
|
var dadosWeedWorker = OperadorErvas?.Clone();
|
|
var dadosVisualWorker = OperadorVisual?.Clone();
|
|
var dadosHealthWorker = OperadorSaude?.Clone();
|
|
var dadosLivox = LivoxLidar?.Clone();
|
|
var dadosCooler = _Cooler?.GetResumo(agora);
|
|
op.Controle.Momento = agora;
|
|
|
|
OperacaoSensoriamentoConjuntoModel dadosAtualizados = new OperacaoSensoriamentoConjuntoModel(op)
|
|
{
|
|
Momento = agora,
|
|
Operacao = dadosOperacao,
|
|
IMU = dadosIMU,
|
|
Atuador = dadosAtuador,
|
|
Sensoriamento = dadosSensoriamento,
|
|
Movimentacao = dadosMovimentacao,
|
|
Direcional = dadosDirecional,
|
|
Bateria = dadosBateria,
|
|
Trajetoria = dadosTrajetoria,
|
|
Gps = dadosGps,
|
|
OperadorSaude = dadosHealthWorker,
|
|
OperadorVisual = dadosVisualWorker,
|
|
OperadorErvas = dadosWeedWorker,
|
|
DadosPerformance = dadosPerformance,
|
|
LivoxLidar = dadosLivox,
|
|
CoolerControl = dadosCooler,
|
|
Logs = op.ListarEventosPendentes(),
|
|
UltimoRegistroLog = UltimoRegistroLog,
|
|
};
|
|
|
|
op.SubstituirSensoriamentoSnapshot(dadosAtualizados);
|
|
}
|
|
|
|
public OperacaoSensoriamentoConjuntoModel Clone()
|
|
{
|
|
return new OperacaoSensoriamentoConjuntoModel(op)
|
|
{
|
|
Momento = Momento,
|
|
Operacao = Operacao?.Clone(),
|
|
Atuador = Atuador?.Clone(),
|
|
Sensoriamento = Sensoriamento?.Clone(),
|
|
Movimentacao = Movimentacao?.Clone(),
|
|
Direcional = Direcional?.Clone(),
|
|
Bateria = Bateria?.Clone(),
|
|
Trajetoria = Trajetoria?.Clone(),
|
|
Gps = Gps?.Clone(),
|
|
OperadorSaude = OperadorSaude?.Clone(),
|
|
OperadorVisual = OperadorVisual?.Clone(),
|
|
OperadorErvas = OperadorErvas?.Clone(),
|
|
DadosPerformance = DadosPerformance?.Clone(),
|
|
IMU = IMU?.Clone(),
|
|
LivoxLidar = LivoxLidar?.Clone(),
|
|
CoolerControl = CoolerControl?.Clone(),
|
|
Logs = new List<OperacaoSensoriamentoLogErrosModel>(Logs ?? new List<OperacaoSensoriamentoLogErrosModel>()),
|
|
UltimoRegistroLog = UltimoRegistroLog,
|
|
};
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public class OperacaoSensoriamentoLogModel
|
|
{
|
|
public DateTime Momento { get; set; }
|
|
public ModoOperacao Modo { get; set; }
|
|
public StatusModulo Status { get; set; }
|
|
public bool ControleAutomatico { get; set; }
|
|
public StatusOperacao StatusOperacaoAtual { get; set; }
|
|
public StatusOperacao StatusOperacaoAnterior { get; set; }
|
|
public string ErroOperacaoLiberada { get; set; }
|
|
public JObject OperacaoLiberacaoDebug { get; set; }
|
|
public bool OperacaoConfigurada { get; set; }
|
|
public bool OperacaoLiberada { get; set; }
|
|
public bool OperacaoIniciada { get; set; }
|
|
public bool Emergencia { get; set; }
|
|
public bool Pausa { get; set; }
|
|
public bool Calibrando { get; set; }
|
|
public bool Finalizando { get; set; }
|
|
public DateTime DataInicio { get; set; }
|
|
public DateTime DataFim { get; set; }
|
|
public double TempoAguardandoSeg { get; set; }
|
|
public double TempoDecorridoSeg { get; set; }
|
|
public DateTime TempoDecorrido
|
|
{
|
|
get
|
|
{
|
|
return new DateTime().AddSeconds(TempoDecorridoSeg);
|
|
}
|
|
}
|
|
|
|
public CanServiceTipo TipoCanAtivo { get; set; }
|
|
|
|
public List<OperacaoModulosMandatoriosModel> ModulosMandatorios { get; set; }
|
|
public List<OperacaoParametrosMandatoriosModel> ParametrosMandatorios { get; set; }
|
|
public List<DispositivoDetalhesModel> DispositivosMapeados { get; set; }
|
|
public Dictionary<T_Code, Dictionary<string, bool>> ModsCalibragem { get; set; }
|
|
public Dictionary<string, Dictionary<string, bool>> ModsCalibragemView { get; set; }
|
|
|
|
public void CopiarEstadoRuntimeDe(OperacaoSensoriamentoLogModel origem)
|
|
{
|
|
if (origem == null)
|
|
return;
|
|
|
|
OperacaoIniciada = origem.OperacaoIniciada;
|
|
Emergencia = origem.Emergencia;
|
|
Pausa = origem.Pausa;
|
|
Calibrando = origem.Calibrando;
|
|
Finalizando = origem.Finalizando;
|
|
DataInicio = origem.DataInicio;
|
|
DataFim = origem.DataFim;
|
|
StatusOperacaoAnterior = origem.StatusOperacaoAnterior;
|
|
}
|
|
|
|
|
|
public OperacaoSensoriamentoLogModel Clone()
|
|
{
|
|
return new OperacaoSensoriamentoLogModel()
|
|
{
|
|
Momento = Momento,
|
|
Modo = Modo,
|
|
ControleAutomatico = ControleAutomatico,
|
|
Status = Status,
|
|
ErroOperacaoLiberada = ErroOperacaoLiberada,
|
|
OperacaoLiberacaoDebug = OperacaoLiberacaoDebug,
|
|
OperacaoConfigurada = OperacaoConfigurada,
|
|
OperacaoLiberada = OperacaoLiberada,
|
|
OperacaoIniciada = OperacaoIniciada,
|
|
Emergencia = Emergencia,
|
|
Pausa = Pausa,
|
|
Calibrando = Calibrando,
|
|
Finalizando = Finalizando,
|
|
StatusOperacaoAtual = StatusOperacaoAtual,
|
|
StatusOperacaoAnterior = StatusOperacaoAnterior,
|
|
DataInicio = DataInicio,
|
|
DataFim = DataFim,
|
|
TempoAguardandoSeg = TempoAguardandoSeg,
|
|
TempoDecorridoSeg = TempoDecorridoSeg,
|
|
TipoCanAtivo = TipoCanAtivo,
|
|
ModulosMandatorios = new List<OperacaoModulosMandatoriosModel>(ModulosMandatorios ?? new List<OperacaoModulosMandatoriosModel>()),
|
|
ParametrosMandatorios = new List<OperacaoParametrosMandatoriosModel>(ParametrosMandatorios ?? new List<OperacaoParametrosMandatoriosModel>()),
|
|
DispositivosMapeados = new List<DispositivoDetalhesModel>(DispositivosMapeados ?? new List<DispositivoDetalhesModel>()),
|
|
ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>(ModsCalibragem ?? new Dictionary<T_Code, Dictionary<string, bool>>()),
|
|
ModsCalibragemView = new Dictionary<string, Dictionary<string, bool>>(ModsCalibragemView),
|
|
};
|
|
}
|
|
|
|
}
|
|
|
|
public class OperacaoSensoriamentoLogImuModel
|
|
{
|
|
public bool Iniciado { get; set; }
|
|
public double InclinacaoLateral { get; set; }
|
|
public double InclinacaoFrontal { get; set; }
|
|
public double Rotacao { get; set; }
|
|
public double RotacaoCorrigida { get; set; }
|
|
public bool EmMovimento { get; set; }
|
|
public double IndiceMovimento { get; set; }
|
|
public double IndiceRugosidade { get; set; }
|
|
public double IndiceEstabilidade { get; set; }
|
|
public double IndiceImpacto { get; set; }
|
|
|
|
public OperacaoSensoriamentoLogImuModel Clone()
|
|
{
|
|
return new OperacaoSensoriamentoLogImuModel()
|
|
{
|
|
Iniciado = Iniciado,
|
|
InclinacaoLateral = InclinacaoLateral,
|
|
InclinacaoFrontal = InclinacaoFrontal,
|
|
Rotacao = Rotacao,
|
|
RotacaoCorrigida = RotacaoCorrigida,
|
|
EmMovimento = EmMovimento,
|
|
IndiceMovimento = IndiceMovimento,
|
|
IndiceImpacto = IndiceImpacto,
|
|
IndiceEstabilidade = IndiceEstabilidade,
|
|
IndiceRugosidade = IndiceRugosidade,
|
|
};
|
|
}
|
|
}
|
|
|
|
public class OperacaoSensoriamentoLogBateriaModel
|
|
{
|
|
public DateTime Momento { get; set; }
|
|
public bool Iniciado { get; set; }
|
|
public bool BmsLigado { get; set; }
|
|
public double _dt { get; set; }
|
|
public double PercentualBateria { get; set; }
|
|
public double PercentualBateriaConsumida { get; set; }
|
|
public double PercentualBateriaConsumidaOperacao { get; set; }
|
|
public double CorrenteInstantanea { get; set; }
|
|
public double TensaoInstantanea { get; set; }
|
|
public double PotenciaInstantanea { get; set; }
|
|
public double WhPorMetro { get; set; }
|
|
public double TempoEstimadoRestanteMinutos { get; set; }
|
|
public double DistanciaEstimadaRestanteMetros { get; set; }
|
|
public double Temperatura { get; set; }
|
|
public List<OperacaoSensoriamentoLogBateriaBarramentoModel> Barramentos { get; set; }
|
|
|
|
public OperacaoSensoriamentoLogBateriaModel Clone()
|
|
{
|
|
return new OperacaoSensoriamentoLogBateriaModel()
|
|
{
|
|
Momento = Momento,
|
|
Iniciado = Iniciado,
|
|
BmsLigado = BmsLigado,
|
|
_dt = _dt,
|
|
PercentualBateriaConsumida = PercentualBateriaConsumida,
|
|
PercentualBateriaConsumidaOperacao = PercentualBateriaConsumidaOperacao,
|
|
PercentualBateria = PercentualBateria,
|
|
CorrenteInstantanea = CorrenteInstantanea,
|
|
TensaoInstantanea = TensaoInstantanea,
|
|
PotenciaInstantanea = PotenciaInstantanea,
|
|
WhPorMetro = WhPorMetro,
|
|
TempoEstimadoRestanteMinutos = TempoEstimadoRestanteMinutos,
|
|
DistanciaEstimadaRestanteMetros = DistanciaEstimadaRestanteMetros,
|
|
Temperatura = Temperatura,
|
|
Barramentos = new List<OperacaoSensoriamentoLogBateriaBarramentoModel>(Barramentos ?? new List<OperacaoSensoriamentoLogBateriaBarramentoModel>())
|
|
};
|
|
}
|
|
}
|
|
|
|
public class OperacaoSensoriamentoLogBateriaBarramentoModel
|
|
{
|
|
public string ID { get; set; }
|
|
public bool Iniciado { get; set; }
|
|
public string Descricao { get; set; }
|
|
public double Tensao { get; set; }
|
|
public double Corrente { get; set; }
|
|
public double Potencia { get; set; }
|
|
public double Energia { get; set; }
|
|
public double Temperatura { get; set; }
|
|
}
|
|
|
|
public class OperacaoSensoriamentoLogTrajetoriaModel
|
|
{
|
|
public DateTime Momento { get; set; }
|
|
public StatusCarroMapa StatusCarro { get; set; }
|
|
public bool TrajetoriaConcluida { get; set; }
|
|
public double ProgressoTrajeto { get; set; }
|
|
public double AnguloCaminho { get; set; }
|
|
public double AnguloMedioCorredor { get; set; }
|
|
public DirecaoCarroRua DirecaoCaminho { get; set; }
|
|
public CorredorTrajetoriaModel CorredorAtual { get; set; }
|
|
public double DistanciaEsquerda { get; set; }
|
|
public double DistanciaDireita { get; set; }
|
|
public double DistanciaTotal { get; set; }
|
|
public double DistanciaPercorrida { get; set; }
|
|
public double DistanciaRestante { get; set; }
|
|
public bool NaMargemDoCorredor { get; set; }
|
|
public bool ManobrandoEntreRuas { get; set; }
|
|
public string TempoEstimadoRestante { get; set; }
|
|
public string TempoEstimadoOperacao { get; set; }
|
|
public PontoTrajetoriaModel ProximoPonto { get; set; }
|
|
public PontoTrajetoriaModel PontoAtual { get; set; }
|
|
public PontoTrajetoriaModel PontoMaisProximo { get; set; }
|
|
|
|
public double ErroOrientacaoAngular { get; set; }
|
|
public double ErroOrientacaoAngularCombinado { get; set; }
|
|
public double ErroOrientacaoAngularCaminho { get; set; }
|
|
public double ErroOrientacaoAngularProximoPonto { get; set; }
|
|
public double ErroLateralAngular { get; set; }
|
|
|
|
public int IdxRuaAtual { get; set; }
|
|
public double PercentualOperacao { get; set; }
|
|
public double PercentualRuaAtual { get; set; }
|
|
public int QtdPontos { get; set; }
|
|
|
|
public GPSModel PrimeiroPontoDentroMapa { get; set; }
|
|
public GPSModel PrimeiroPontoDentroCana { get; set; }
|
|
public double DistanciaErroMapaCana { get; set; }
|
|
|
|
public AutonomiaCorredorModel AutonomiaCooredor { get; set; }
|
|
|
|
public OperacaoSensoriamentoLogTrajetoriaModel Clone()
|
|
{
|
|
return new OperacaoSensoriamentoLogTrajetoriaModel()
|
|
{
|
|
Momento = Momento,
|
|
StatusCarro = StatusCarro,
|
|
TrajetoriaConcluida = TrajetoriaConcluida,
|
|
AnguloCaminho = AnguloCaminho,
|
|
AnguloMedioCorredor = AnguloMedioCorredor,
|
|
DirecaoCaminho = DirecaoCaminho,
|
|
DistanciaDireita = DistanciaDireita,
|
|
DistanciaEsquerda = DistanciaEsquerda,
|
|
CorredorAtual = CorredorAtual?.Clone(false),
|
|
ProgressoTrajeto = ProgressoTrajeto,
|
|
DistanciaTotal = DistanciaTotal,
|
|
DistanciaPercorrida = DistanciaPercorrida,
|
|
DistanciaRestante = DistanciaRestante,
|
|
NaMargemDoCorredor = NaMargemDoCorredor,
|
|
ManobrandoEntreRuas = ManobrandoEntreRuas,
|
|
TempoEstimadoRestante = TempoEstimadoRestante,
|
|
TempoEstimadoOperacao = TempoEstimadoOperacao,
|
|
ErroLateralAngular = ErroLateralAngular,
|
|
ErroOrientacaoAngularCombinado = ErroOrientacaoAngularCombinado,
|
|
ErroOrientacaoAngular = ErroOrientacaoAngular,
|
|
ErroOrientacaoAngularCaminho = ErroOrientacaoAngularCaminho,
|
|
ErroOrientacaoAngularProximoPonto = ErroOrientacaoAngularProximoPonto,
|
|
ProximoPonto = ProximoPonto?.Clone(),
|
|
PontoAtual = PontoAtual?.Clone(),
|
|
PontoMaisProximo = PontoMaisProximo?.Clone(),
|
|
IdxRuaAtual = IdxRuaAtual,
|
|
PercentualOperacao = PercentualOperacao,
|
|
PercentualRuaAtual = PercentualRuaAtual,
|
|
QtdPontos = QtdPontos,
|
|
PrimeiroPontoDentroCana = PrimeiroPontoDentroCana?.Clone(),
|
|
PrimeiroPontoDentroMapa = PrimeiroPontoDentroMapa?.Clone(),
|
|
DistanciaErroMapaCana = DistanciaErroMapaCana,
|
|
AutonomiaCooredor = AutonomiaCooredor?.Clone()
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
// Atuador
|
|
public class AtuadorLogModel
|
|
{
|
|
public DateTime Momento { get; set; }
|
|
|
|
// Conexão / saúde geral
|
|
public bool Inicializado { get; set; }
|
|
public bool ConexaoAtiva { get; set; }
|
|
public int LatenciaLoop { get; set; }
|
|
public DateTime UltimoComandoRespondido { get; set; }
|
|
|
|
// Contexto da operação
|
|
public int QtdCamerasSolo { get; set; }
|
|
public int QuantidadeBicos { get; set; }
|
|
public double CapacidadeReservatorio { get; set; }
|
|
|
|
// Reservatório / consumo
|
|
public double MassaReservatorio { get; set; }
|
|
public double VolumeReservatorio { get; set; }
|
|
public double PercentualReservatorio { get; set; }
|
|
|
|
public double HerbicidaConsumido { get; set; }
|
|
public double HerbicidaConsumidoOperacao { get; set; }
|
|
public double PercentualHerbicidaConsumido { get; set; }
|
|
public double PercentualHerbicidaConsumidoOperacao { get; set; }
|
|
|
|
public double HerbicidaPorAtuacao { get; set; }
|
|
public double HerbicidaPorErva { get; set; }
|
|
|
|
// Ervas / contexto visual
|
|
public bool ErvasNoRadar { get; set; }
|
|
public double PercentualErvasNoRadar { get; set; }
|
|
public double PercentualErvasTerreno { get; set; }
|
|
|
|
// Pressão / vazão
|
|
public double PressaoLinha_SP { get; set; }
|
|
public double PressaoLinha { get; set; }
|
|
public double PressaoLinhaCalc { get; set; }
|
|
public double PressaoAtualBomba { get; set; }
|
|
|
|
public double VazaoFluxoMLpSInstantanea { get; set; }
|
|
public double VazaoFluxoMLpSInstantaneaCorrigida { get; set; }
|
|
public double VazaoFluxoMLpSMedia { get; set; }
|
|
|
|
public double VolumeVazaoML { get; set; }
|
|
|
|
// Bomba linha
|
|
public bool BombaLigada { get; set; }
|
|
public bool ComandoBomba { get; set; }
|
|
public bool LeituraComandoBomba { get; set; }
|
|
|
|
// Mantém nomes úteis para tela/log antigo
|
|
public double PotenciaBomba { get; set; }
|
|
public double LeituraPotenciaBomba { get; set; }
|
|
|
|
// Novos dados da bomba via Dados2
|
|
public int QtdBicosLigados { get; set; }
|
|
public double PotenciaFeedForward { get; set; }
|
|
public double PotenciaFinal { get; set; }
|
|
public double PressaoSensor { get; set; }
|
|
public double PressaoSPControle { get; set; }
|
|
|
|
// Flags de cavitaao
|
|
public bool PressaoSPForaDoMapa { get; set; }
|
|
public bool FluxoInsuficiente { get; set; }
|
|
public bool RecuperacaoFluxoAtiva { get; set; }
|
|
public bool CavitacaoSuspeita { get; set; }
|
|
public bool Cavitada { get; set; }
|
|
public bool CorteSegurancaAtivo { get; set; }
|
|
public bool PressaoSPLimitadoPorCapacidade { get; set; }
|
|
|
|
public double TempoPulverizadorAtuado { get; set; }
|
|
public double TempoBombaAtuada { get; set; }
|
|
public bool BombaCavitada { get; set; }
|
|
|
|
// Agitador
|
|
public ModoAgitadorCalda ModoControleAgitador { get; set; }
|
|
public double PotenciaAgitador { get; set; }
|
|
|
|
// Barra
|
|
public double AnguloBarraEsquerda { get; set; }
|
|
public double AnguloBarraDireita { get; set; }
|
|
|
|
// Autonomia / estimativas
|
|
public double LPorMetro { get; set; }
|
|
public double LPorMinuto { get; set; }
|
|
public double TempoEstimadoRestanteMinutos { get; set; }
|
|
public double DistanciaEstimadaRestanteMetros { get; set; }
|
|
|
|
// Componentes
|
|
public Dictionary<string, bool> Iniciados { get; set; } = new Dictionary<string, bool>();
|
|
public List<AtuadorBicoLogModel> Bicos { get; set; } = new List<AtuadorBicoLogModel>();
|
|
|
|
public AtuadorLogModel Clone()
|
|
{
|
|
return new AtuadorLogModel()
|
|
{
|
|
Momento = Momento,
|
|
|
|
Inicializado = Inicializado,
|
|
ConexaoAtiva = ConexaoAtiva,
|
|
LatenciaLoop = LatenciaLoop,
|
|
UltimoComandoRespondido = UltimoComandoRespondido,
|
|
|
|
QtdCamerasSolo = QtdCamerasSolo,
|
|
QuantidadeBicos = QuantidadeBicos,
|
|
CapacidadeReservatorio = CapacidadeReservatorio,
|
|
|
|
MassaReservatorio = MassaReservatorio,
|
|
VolumeReservatorio = VolumeReservatorio,
|
|
PercentualReservatorio = PercentualReservatorio,
|
|
|
|
HerbicidaConsumido = HerbicidaConsumido,
|
|
HerbicidaConsumidoOperacao = HerbicidaConsumidoOperacao,
|
|
PercentualHerbicidaConsumido = PercentualHerbicidaConsumido,
|
|
PercentualHerbicidaConsumidoOperacao = PercentualHerbicidaConsumidoOperacao,
|
|
|
|
HerbicidaPorAtuacao = HerbicidaPorAtuacao,
|
|
HerbicidaPorErva = HerbicidaPorErva,
|
|
|
|
ErvasNoRadar = ErvasNoRadar,
|
|
PercentualErvasNoRadar = PercentualErvasNoRadar,
|
|
PercentualErvasTerreno = PercentualErvasTerreno,
|
|
|
|
PressaoLinha_SP = PressaoLinha_SP,
|
|
PressaoLinha = PressaoLinha,
|
|
PressaoLinhaCalc = PressaoLinhaCalc,
|
|
PressaoAtualBomba = PressaoAtualBomba,
|
|
|
|
VazaoFluxoMLpSInstantanea = VazaoFluxoMLpSInstantanea,
|
|
VazaoFluxoMLpSInstantaneaCorrigida = VazaoFluxoMLpSInstantaneaCorrigida,
|
|
VazaoFluxoMLpSMedia = VazaoFluxoMLpSMedia,
|
|
VolumeVazaoML = VolumeVazaoML,
|
|
|
|
BombaLigada = BombaLigada,
|
|
ComandoBomba = ComandoBomba,
|
|
LeituraComandoBomba = LeituraComandoBomba,
|
|
|
|
PotenciaBomba = PotenciaBomba,
|
|
LeituraPotenciaBomba = LeituraPotenciaBomba,
|
|
|
|
QtdBicosLigados = QtdBicosLigados,
|
|
PotenciaFeedForward = PotenciaFeedForward,
|
|
PotenciaFinal = PotenciaFinal,
|
|
PressaoSensor = PressaoSensor,
|
|
PressaoSPControle = PressaoSPControle,
|
|
|
|
PressaoSPForaDoMapa = PressaoSPForaDoMapa,
|
|
FluxoInsuficiente = FluxoInsuficiente,
|
|
RecuperacaoFluxoAtiva = RecuperacaoFluxoAtiva,
|
|
CavitacaoSuspeita = CavitacaoSuspeita,
|
|
Cavitada = Cavitada,
|
|
CorteSegurancaAtivo = CorteSegurancaAtivo,
|
|
PressaoSPLimitadoPorCapacidade = PressaoSPLimitadoPorCapacidade,
|
|
|
|
TempoPulverizadorAtuado = TempoPulverizadorAtuado,
|
|
TempoBombaAtuada = TempoBombaAtuada,
|
|
BombaCavitada = BombaCavitada,
|
|
|
|
ModoControleAgitador = ModoControleAgitador,
|
|
PotenciaAgitador = PotenciaAgitador,
|
|
|
|
AnguloBarraEsquerda = AnguloBarraEsquerda,
|
|
AnguloBarraDireita = AnguloBarraDireita,
|
|
|
|
LPorMetro = LPorMetro,
|
|
LPorMinuto = LPorMinuto,
|
|
TempoEstimadoRestanteMinutos = TempoEstimadoRestanteMinutos,
|
|
DistanciaEstimadaRestanteMetros = DistanciaEstimadaRestanteMetros,
|
|
|
|
Iniciados = new Dictionary<string, bool>(Iniciados ?? new Dictionary<string, bool>()),
|
|
Bicos = Bicos?.Select(b => b.Clone()).ToList() ?? new List<AtuadorBicoLogModel>()
|
|
};
|
|
}
|
|
|
|
}
|
|
|
|
public class AtuadorBicoLogModel
|
|
{
|
|
public string ID { get; set; }
|
|
public bool Inicializado { get; set; }
|
|
public bool Comandar { get; set; }
|
|
public bool Atuado { get; set; }
|
|
public double MediaNivelFluxo { get; set; }
|
|
public int Posicao { get; set; }
|
|
public bool StatusBico { get; set; }
|
|
public int Atuacoes { get; set; }
|
|
public double TempoAtuado { get; set; }
|
|
public double AnguloAbertura { get; set; }
|
|
public bool ComMovimento { get; set; }
|
|
public double AnguloControle { get; set; }
|
|
|
|
public AtuadorBicoLogModel Clone()
|
|
{
|
|
return new AtuadorBicoLogModel()
|
|
{
|
|
ID = ID,
|
|
Inicializado = Inicializado,
|
|
Comandar = Comandar,
|
|
Atuado = Atuado,
|
|
MediaNivelFluxo = MediaNivelFluxo,
|
|
Posicao = Posicao,
|
|
StatusBico = StatusBico,
|
|
Atuacoes = Atuacoes,
|
|
TempoAtuado = TempoAtuado,
|
|
AnguloAbertura = AnguloAbertura,
|
|
ComMovimento = ComMovimento,
|
|
AnguloControle = AnguloControle
|
|
};
|
|
}
|
|
}
|
|
|
|
// Movimentacao
|
|
public class MovimentacaoLogModel
|
|
{
|
|
public DateTime Momento { get; set; } = DateTime.Now;
|
|
|
|
// Resumo geral do módulo MOV
|
|
public bool Disponivel { get; set; }
|
|
public int TotalModulos { get; set; }
|
|
public int ModulosInicializados { get; set; }
|
|
|
|
public double VelocidadeMediaMs { get; set; }
|
|
public double RPMRodaMedio { get; set; }
|
|
public double RPMMotorMedio { get; set; }
|
|
public double TemperaturaMotorMedia { get; set; }
|
|
public double TemperaturaDriverMedia { get; set; }
|
|
|
|
public double TempoMovimentoSegs { get; set; }
|
|
public TimeSpan TempoMovimento => TimeSpan.FromSeconds(TempoMovimentoSegs);
|
|
|
|
public double DistanciaPercorridaTotal { get; set; }
|
|
public double DistanciaPercorridaParcial { get; set; }
|
|
|
|
public MovimentacaoStatusLadoLogModel EsqStatus { get; set; } = new MovimentacaoStatusLadoLogModel();
|
|
public MovimentacaoStatusLadoLogModel DirStatus { get; set; } = new MovimentacaoStatusLadoLogModel();
|
|
|
|
public bool StatusGeralOk =>
|
|
Disponivel &&
|
|
EsqStatus.Ok &&
|
|
DirStatus.Ok &&
|
|
ModulosInicializados > 0 &&
|
|
!Modulos.Any(x => x.AlarmeMotor || x.AlarmeComando || x.AlarmeSensores);
|
|
|
|
public List<MovimentacaoModuloLogModel> Modulos { get; set; } = new List<MovimentacaoModuloLogModel>();
|
|
|
|
public MovimentacaoLogModel Clone()
|
|
{
|
|
return new MovimentacaoLogModel
|
|
{
|
|
Momento = Momento,
|
|
Disponivel = Disponivel,
|
|
TotalModulos = TotalModulos,
|
|
ModulosInicializados = ModulosInicializados,
|
|
|
|
VelocidadeMediaMs = VelocidadeMediaMs,
|
|
RPMRodaMedio = RPMRodaMedio,
|
|
RPMMotorMedio = RPMMotorMedio,
|
|
TemperaturaMotorMedia = TemperaturaMotorMedia,
|
|
TemperaturaDriverMedia = TemperaturaDriverMedia,
|
|
|
|
TempoMovimentoSegs = TempoMovimentoSegs,
|
|
DistanciaPercorridaTotal = DistanciaPercorridaTotal,
|
|
DistanciaPercorridaParcial = DistanciaPercorridaParcial,
|
|
|
|
EsqStatus = EsqStatus?.Clone() ?? new MovimentacaoStatusLadoLogModel(),
|
|
DirStatus = DirStatus?.Clone() ?? new MovimentacaoStatusLadoLogModel(),
|
|
|
|
Modulos = Modulos?.Select(x => x.Clone()).ToList() ?? new List<MovimentacaoModuloLogModel>()
|
|
};
|
|
}
|
|
}
|
|
|
|
public class MovimentacaoStatusLadoLogModel
|
|
{
|
|
public bool Ok { get; set; }
|
|
public List<string> Motivos { get; set; } = new List<string>();
|
|
|
|
public MovimentacaoStatusLadoLogModel Clone()
|
|
{
|
|
return new MovimentacaoStatusLadoLogModel
|
|
{
|
|
Ok = Ok,
|
|
Motivos = new List<string>(Motivos ?? new List<string>())
|
|
};
|
|
}
|
|
}
|
|
|
|
public class MovimentacaoModuloLogModel
|
|
{
|
|
public string Modulo_ID { get; set; }
|
|
|
|
public byte EnderecoCanTx { get; set; }
|
|
public byte EnderecoCanRx { get; set; }
|
|
|
|
// Estado base
|
|
public bool Inicializado { get; set; }
|
|
public bool Comandar { get; set; }
|
|
public bool AtivadoLeitura { get; set; }
|
|
public bool AtivadoComando { get; set; }
|
|
|
|
// Setpoints e leitura mecânica
|
|
public int RPM_SP { get; set; }
|
|
public int RPM_SP_Controle { get; set; }
|
|
public int RPM_SP_RodaEstimado { get; set; }
|
|
|
|
public double RPM_Motor { get; set; }
|
|
public double RPM_Roda { get; set; }
|
|
public double VelocidadeInstantaneaMs { get; set; }
|
|
|
|
public Sentido Sentido_SP { get; set; }
|
|
public Sentido SentidoLeitura { get; set; }
|
|
|
|
// Elétrica / driver
|
|
public double Tensao { get; set; }
|
|
public double CorrenteMotor { get; set; }
|
|
public double CorrenteBarramento { get; set; }
|
|
public double Potencia { get; set; }
|
|
public double CicloTrabalho { get; set; }
|
|
|
|
// Temperaturas
|
|
public double TemperaturaMotor { get; set; }
|
|
public double TemperaturaDriver { get; set; }
|
|
|
|
// Alarmes
|
|
public OidCodigoErro CodigoAlarme { get; set; }
|
|
public bool AlarmeMotor { get; set; }
|
|
public bool AlarmeSensores { get; set; }
|
|
public bool AlarmeComando { get; set; }
|
|
|
|
// Freio
|
|
public bool FreadoLeituraOid { get; set; }
|
|
public bool FreioSP { get; set; }
|
|
public bool FreioServoLeitura { get; set; }
|
|
public int FreioServoAnguloControle { get; set; }
|
|
public bool FreioServoComandoPendente { get; set; }
|
|
public DateTime FreioServoUltimoEnvio { get; set; }
|
|
|
|
// Comando / debug de controle
|
|
public DateTime UltimoComandoEnviado { get; set; }
|
|
public DateTime UltimoComandoRespondido { get; set; }
|
|
public OidFuncCode UltimoModoControleEnviado { get; set; }
|
|
public double UltimoSetPointEnviado { get; set; }
|
|
public Direcao UltimaDirecao { get; set; }
|
|
|
|
// Compensação em curva
|
|
public double FatorCompensacaoCurva { get; set; } = 1.0;
|
|
|
|
public MovimentacaoModuloLogModel Clone()
|
|
{
|
|
return (MovimentacaoModuloLogModel)MemberwiseClone();
|
|
}
|
|
}
|
|
|
|
// Direcional
|
|
public class DirecionalLogModel
|
|
{
|
|
public DateTime Momento { get; set; } = DateTime.Now;
|
|
|
|
// Resumo geral DIR
|
|
public bool Disponivel { get; set; }
|
|
public int TotalModulos { get; set; }
|
|
public int ModulosInicializados { get; set; }
|
|
public int ModulosControlando { get; set; }
|
|
|
|
public TipoMovimentoDirecional TipoMovimento { get; set; }
|
|
public Direcao UltimaDirecaoControle { get; set; }
|
|
|
|
public double AnguloMedioAbs { get; set; }
|
|
public double AnguloSPMedioAbs { get; set; }
|
|
public double ErroAnguloMedioAbs { get; set; }
|
|
|
|
public DirecionalStatusLogModel Status { get; set; } = new DirecionalStatusLogModel();
|
|
|
|
public bool StatusGeralOk =>
|
|
Disponivel &&
|
|
Status.Ok &&
|
|
ModulosInicializados > 0 &&
|
|
!Modulos.Any(x => x.ErroAnguloAbs > 3.0 && x.Controlar);
|
|
|
|
public List<DirecionalModuloLogModel> Modulos { get; set; } = new List<DirecionalModuloLogModel>();
|
|
|
|
public DirecionalLogModel Clone()
|
|
{
|
|
return new DirecionalLogModel
|
|
{
|
|
Momento = Momento,
|
|
|
|
Disponivel = Disponivel,
|
|
TotalModulos = TotalModulos,
|
|
ModulosInicializados = ModulosInicializados,
|
|
ModulosControlando = ModulosControlando,
|
|
|
|
TipoMovimento = TipoMovimento,
|
|
UltimaDirecaoControle = UltimaDirecaoControle,
|
|
|
|
AnguloMedioAbs = AnguloMedioAbs,
|
|
AnguloSPMedioAbs = AnguloSPMedioAbs,
|
|
ErroAnguloMedioAbs = ErroAnguloMedioAbs,
|
|
|
|
Status = Status?.Clone() ?? new DirecionalStatusLogModel(),
|
|
Modulos = Modulos?.Select(x => x.Clone()).ToList() ?? new List<DirecionalModuloLogModel>()
|
|
};
|
|
}
|
|
}
|
|
|
|
public class DirecionalStatusLogModel
|
|
{
|
|
public bool Ok { get; set; }
|
|
public List<string> Motivos { get; set; } = new List<string>();
|
|
|
|
public DirecionalStatusLogModel Clone()
|
|
{
|
|
return new DirecionalStatusLogModel
|
|
{
|
|
Ok = Ok,
|
|
Motivos = new List<string>(Motivos ?? new List<string>())
|
|
};
|
|
}
|
|
}
|
|
|
|
public class DirecionalModuloLogModel
|
|
{
|
|
public string Modulo_ID { get; set; }
|
|
|
|
public byte EnderecoCanTx { get; set; }
|
|
public byte EnderecoCanRx { get; set; }
|
|
|
|
// Estado base
|
|
public bool Inicializado { get; set; }
|
|
public bool Controlar { get; set; }
|
|
|
|
// Comando
|
|
public double Angulo_SP { get; set; }
|
|
public Sentido Sentido_SP { get; set; }
|
|
public Direcao UltimaDirecao { get; set; }
|
|
|
|
public int Velocidade { get; set; }
|
|
public double VelocidadePercentual { get; set; }
|
|
public double VelocidadeMax { get; set; }
|
|
|
|
// Leituras de ângulo
|
|
public double AnguloDriver { get; set; }
|
|
public double AnguloReal { get; set; }
|
|
public double AnguloLeitura { get; set; }
|
|
|
|
public bool UsarAnguloSensor { get; set; }
|
|
public bool SensorAnguloRealInicializado { get; set; }
|
|
public bool SensorAnguloRealAferir { get; set; }
|
|
|
|
// Diagnóstico geométrico
|
|
public double ErroAngulo { get; set; }
|
|
public double ErroAnguloAbs { get; set; }
|
|
public bool AtingiuAnguloSP { get; set; }
|
|
public bool RetornandoAzero { get; set; }
|
|
|
|
// Sentido / movimento
|
|
public Sentido SentidoLeitura { get; set; }
|
|
public Sentido SentidoReal { get; set; }
|
|
public double RPM { get; set; }
|
|
public bool EmMovimento { get; set; }
|
|
|
|
// Folga / compensação
|
|
public double FolgaMecanica { get; set; }
|
|
public double AnguloFolgaCompensar { get; set; }
|
|
public double OffsetAnguloReal { get; set; }
|
|
|
|
// Fins de curso / entradas
|
|
public bool IN1_Atuado { get; set; }
|
|
public bool IN2_Atuado { get; set; }
|
|
|
|
// Referenciamento
|
|
public bool Referenciando { get; set; }
|
|
public bool Referenciado { get; set; }
|
|
public DateTime UltimoReferenciamento { get; set; }
|
|
|
|
// Comunicação / comando
|
|
public DateTime UltimoComandoEnviado { get; set; }
|
|
public DateTime UltimoComandoRespondido { get; set; }
|
|
|
|
public DirecionalModuloLogModel Clone()
|
|
{
|
|
return (DirecionalModuloLogModel)MemberwiseClone();
|
|
}
|
|
}
|
|
|
|
// Sensoriamento
|
|
public class SensoriamentoLogModel
|
|
{
|
|
public DateTime Momento { get; set; } = DateTime.Now;
|
|
|
|
// Identidade / conexão
|
|
public bool Disponivel { get; set; }
|
|
public bool Conectado { get; set; }
|
|
public bool ConexaoAtivaHealth { get; set; }
|
|
|
|
public T_Code Dispositivo { get; set; } = T_Code.Sen;
|
|
public int Versao { get; set; }
|
|
public string Mod_ID { get; set; }
|
|
|
|
public byte EnderecoCanTx { get; set; }
|
|
public byte EnderecoCanRx { get; set; }
|
|
|
|
public int TaxaAmostragemMs { get; set; }
|
|
public double FrequenciaBaseHz { get; set; }
|
|
public bool RequisitarDados { get; set; }
|
|
|
|
public int LatenciaLoopMs { get; set; }
|
|
|
|
public DateTime UltimoComandoRespondido { get; set; } = DateTime.MinValue;
|
|
public double IdadeUltimoComandoMs { get; set; }
|
|
|
|
// Resumo geral
|
|
public int TotalSensores { get; set; }
|
|
public int SensoresInicializados { get; set; }
|
|
public int SensoresAferindo { get; set; }
|
|
public int SensoresMandatorios { get; set; }
|
|
public int SensoresMandatoriosOk { get; set; }
|
|
|
|
public int TotalReles { get; set; }
|
|
public int RelesInicializados { get; set; }
|
|
public int RelesControlando { get; set; }
|
|
|
|
public int TotalServos { get; set; }
|
|
public int ServosInicializados { get; set; }
|
|
public int ServosControlando { get; set; }
|
|
|
|
public int TotalSinaleiros { get; set; }
|
|
public int SinaleirosInicializados { get; set; }
|
|
public int SinaleirosControlando { get; set; }
|
|
|
|
public int LeiturasHealthTotal { get; set; }
|
|
public int LeiturasHealthOk { get; set; }
|
|
public int LeiturasHealthForaFaixa { get; set; }
|
|
|
|
public bool ComponentesMandatoriosOk => SensoresMandatorios == SensoresMandatoriosOk;
|
|
|
|
public bool StatusGeralOk =>
|
|
Disponivel &&
|
|
Conectado &&
|
|
ComponentesMandatoriosOk &&
|
|
LeiturasHealthForaFaixa == 0;
|
|
|
|
public List<string> Alertas { get; set; } = new List<string>();
|
|
|
|
public List<SensoriamentoSensorLogModel> Sensores { get; set; } = new List<SensoriamentoSensorLogModel>();
|
|
public List<SensoriamentoSinaleiroLogModel> Sinaleiros { get; set; } = new List<SensoriamentoSinaleiroLogModel>();
|
|
public List<SensoriamentoReleLogModel> Reles { get; set; } = new List<SensoriamentoReleLogModel>();
|
|
public List<SensoriamentoServoLogModel> Servos { get; set; } = new List<SensoriamentoServoLogModel>();
|
|
|
|
public SensoriamentoLogModel Clone()
|
|
{
|
|
return new SensoriamentoLogModel
|
|
{
|
|
Momento = Momento,
|
|
|
|
Disponivel = Disponivel,
|
|
Conectado = Conectado,
|
|
ConexaoAtivaHealth = ConexaoAtivaHealth,
|
|
|
|
Dispositivo = Dispositivo,
|
|
Versao = Versao,
|
|
Mod_ID = Mod_ID,
|
|
|
|
EnderecoCanTx = EnderecoCanTx,
|
|
EnderecoCanRx = EnderecoCanRx,
|
|
|
|
TaxaAmostragemMs = TaxaAmostragemMs,
|
|
FrequenciaBaseHz = FrequenciaBaseHz,
|
|
RequisitarDados = RequisitarDados,
|
|
|
|
LatenciaLoopMs = LatenciaLoopMs,
|
|
|
|
UltimoComandoRespondido = UltimoComandoRespondido,
|
|
IdadeUltimoComandoMs = IdadeUltimoComandoMs,
|
|
|
|
TotalSensores = TotalSensores,
|
|
SensoresInicializados = SensoresInicializados,
|
|
SensoresAferindo = SensoresAferindo,
|
|
SensoresMandatorios = SensoresMandatorios,
|
|
SensoresMandatoriosOk = SensoresMandatoriosOk,
|
|
|
|
TotalReles = TotalReles,
|
|
RelesInicializados = RelesInicializados,
|
|
RelesControlando = RelesControlando,
|
|
|
|
TotalServos = TotalServos,
|
|
ServosInicializados = ServosInicializados,
|
|
ServosControlando = ServosControlando,
|
|
|
|
TotalSinaleiros = TotalSinaleiros,
|
|
SinaleirosInicializados = SinaleirosInicializados,
|
|
SinaleirosControlando = SinaleirosControlando,
|
|
|
|
LeiturasHealthTotal = LeiturasHealthTotal,
|
|
LeiturasHealthOk = LeiturasHealthOk,
|
|
LeiturasHealthForaFaixa = LeiturasHealthForaFaixa,
|
|
|
|
Alertas = new List<string>(Alertas ?? new List<string>()),
|
|
|
|
Sensores = Sensores?.Select(x => x.Clone()).ToList() ?? new List<SensoriamentoSensorLogModel>(),
|
|
Sinaleiros = Sinaleiros?.Select(x => x.Clone()).ToList() ?? new List<SensoriamentoSinaleiroLogModel>(),
|
|
Reles = Reles?.Select(x => x.Clone()).ToList() ?? new List<SensoriamentoReleLogModel>(),
|
|
Servos = Servos?.Select(x => x.Clone()).ToList() ?? new List<SensoriamentoServoLogModel>(),
|
|
};
|
|
}
|
|
}
|
|
|
|
public class SensoriamentoLeituraLogModel
|
|
{
|
|
public FuncoesPinout Funcao { get; set; }
|
|
public CanMessagePosicaoDados Posicao { get; set; }
|
|
public int Indice { get; set; }
|
|
|
|
public object Valor { get; set; }
|
|
public string ValorTexto { get; set; }
|
|
public double? ValorNumerico { get; set; }
|
|
public bool? ValorBool { get; set; }
|
|
|
|
public string UnidadeMedida { get; set; }
|
|
|
|
public bool AnaliseHealth { get; set; }
|
|
public double Minimo { get; set; }
|
|
public double Maximo { get; set; }
|
|
public double Nominal { get; set; }
|
|
|
|
public bool? DentroFaixa { get; set; }
|
|
|
|
public DateTime LidoEm { get; set; } = DateTime.MinValue;
|
|
public double IdadeMs { get; set; }
|
|
|
|
public SensoriamentoLeituraLogModel Clone()
|
|
{
|
|
return (SensoriamentoLeituraLogModel)MemberwiseClone();
|
|
}
|
|
}
|
|
|
|
public class SensoriamentoSensorLogModel
|
|
{
|
|
public string ID { get; set; }
|
|
public int ID_Num { get; set; }
|
|
public string Descricao { get; set; }
|
|
public S_Code Componente { get; set; }
|
|
|
|
public bool Aferir { get; set; }
|
|
public bool Mandatorio { get; set; }
|
|
public bool Inicializado { get; set; }
|
|
public bool Liberado { get; set; }
|
|
|
|
public DateTime UltimaLeitura { get; set; } = DateTime.MinValue;
|
|
public double IdadeUltimaLeituraMs { get; set; }
|
|
|
|
public List<SensoriamentoLeituraLogModel> Leituras { get; set; } = new List<SensoriamentoLeituraLogModel>();
|
|
|
|
public SensoriamentoSensorLogModel Clone()
|
|
{
|
|
return new SensoriamentoSensorLogModel
|
|
{
|
|
ID = ID,
|
|
ID_Num = ID_Num,
|
|
Descricao = Descricao,
|
|
Componente = Componente,
|
|
|
|
Aferir = Aferir,
|
|
Mandatorio = Mandatorio,
|
|
Inicializado = Inicializado,
|
|
Liberado = Liberado,
|
|
|
|
UltimaLeitura = UltimaLeitura,
|
|
IdadeUltimaLeituraMs = IdadeUltimaLeituraMs,
|
|
|
|
Leituras = Leituras?.Select(x => x.Clone()).ToList() ?? new List<SensoriamentoLeituraLogModel>()
|
|
};
|
|
}
|
|
}
|
|
|
|
public class SensoriamentoSinaleiroLogModel
|
|
{
|
|
public string ID { get; set; }
|
|
public int ID_Num { get; set; }
|
|
public string Descricao { get; set; }
|
|
public S_Code Componente { get; set; }
|
|
|
|
public bool Controlar { get; set; }
|
|
public bool Mandatorio { get; set; }
|
|
public bool Inicializado { get; set; }
|
|
|
|
public int StatusLedIdLeitura { get; set; }
|
|
public StatusLED StatusLedLeitura { get; set; }
|
|
|
|
public int StatusLedIdDesejado { get; set; }
|
|
public StatusLED StatusLedDesejado { get; set; }
|
|
public StatusOperacao? StatusOperacaoDesejado { get; set; }
|
|
|
|
public int QtdPiscadasDesejado { get; set; }
|
|
public int TempoMsDesejado { get; set; }
|
|
public int PausaMsDesejado { get; set; }
|
|
|
|
public bool Divergente { get; set; }
|
|
|
|
public DateTime UltimaLeitura { get; set; } = DateTime.MinValue;
|
|
public DateTime UltimoComandoEnviado { get; set; } = DateTime.MinValue;
|
|
public double IdadeUltimaLeituraMs { get; set; }
|
|
|
|
public List<SensoriamentoLeituraLogModel> Leituras { get; set; } = new List<SensoriamentoLeituraLogModel>();
|
|
|
|
public SensoriamentoSinaleiroLogModel Clone()
|
|
{
|
|
return new SensoriamentoSinaleiroLogModel
|
|
{
|
|
ID = ID,
|
|
ID_Num = ID_Num,
|
|
Descricao = Descricao,
|
|
Componente = Componente,
|
|
|
|
Controlar = Controlar,
|
|
Mandatorio = Mandatorio,
|
|
Inicializado = Inicializado,
|
|
|
|
StatusLedIdLeitura = StatusLedIdLeitura,
|
|
StatusLedLeitura = StatusLedLeitura,
|
|
|
|
StatusLedIdDesejado = StatusLedIdDesejado,
|
|
StatusLedDesejado = StatusLedDesejado,
|
|
StatusOperacaoDesejado = StatusOperacaoDesejado,
|
|
|
|
QtdPiscadasDesejado = QtdPiscadasDesejado,
|
|
TempoMsDesejado = TempoMsDesejado,
|
|
PausaMsDesejado = PausaMsDesejado,
|
|
|
|
Divergente = Divergente,
|
|
|
|
UltimaLeitura = UltimaLeitura,
|
|
UltimoComandoEnviado = UltimoComandoEnviado,
|
|
IdadeUltimaLeituraMs = IdadeUltimaLeituraMs,
|
|
|
|
Leituras = Leituras?.Select(x => x.Clone()).ToList() ?? new List<SensoriamentoLeituraLogModel>()
|
|
};
|
|
}
|
|
}
|
|
|
|
public class SensoriamentoReleLogModel
|
|
{
|
|
public string ID { get; set; }
|
|
public int ID_Num { get; set; }
|
|
public string Descricao { get; set; }
|
|
public S_Code Componente { get; set; }
|
|
|
|
public bool Controlar { get; set; }
|
|
public bool Mandatorio { get; set; }
|
|
public bool Inicializado { get; set; }
|
|
public bool Liberado { get; set; }
|
|
|
|
public bool AtuacaoNivelAlto { get; set; }
|
|
|
|
public Estado EstadoControle { get; set; }
|
|
public Estado EstadoLeitura { get; set; }
|
|
public Estado UltimoEstadoDesejado { get; set; }
|
|
|
|
public bool Divergente { get; set; }
|
|
|
|
public DateTime UltimaLeitura { get; set; } = DateTime.MinValue;
|
|
public DateTime UltimoComandoEnviado { get; set; } = DateTime.MinValue;
|
|
public double IdadeUltimaLeituraMs { get; set; }
|
|
|
|
public List<SensoriamentoLeituraLogModel> Leituras { get; set; } = new List<SensoriamentoLeituraLogModel>();
|
|
|
|
public SensoriamentoReleLogModel Clone()
|
|
{
|
|
return new SensoriamentoReleLogModel
|
|
{
|
|
ID = ID,
|
|
ID_Num = ID_Num,
|
|
Descricao = Descricao,
|
|
Componente = Componente,
|
|
|
|
Controlar = Controlar,
|
|
Mandatorio = Mandatorio,
|
|
Inicializado = Inicializado,
|
|
Liberado = Liberado,
|
|
|
|
AtuacaoNivelAlto = AtuacaoNivelAlto,
|
|
|
|
EstadoControle = EstadoControle,
|
|
EstadoLeitura = EstadoLeitura,
|
|
UltimoEstadoDesejado = UltimoEstadoDesejado,
|
|
|
|
Divergente = Divergente,
|
|
|
|
UltimaLeitura = UltimaLeitura,
|
|
UltimoComandoEnviado = UltimoComandoEnviado,
|
|
IdadeUltimaLeituraMs = IdadeUltimaLeituraMs,
|
|
|
|
Leituras = Leituras?.Select(x => x.Clone()).ToList() ?? new List<SensoriamentoLeituraLogModel>()
|
|
};
|
|
}
|
|
}
|
|
|
|
public class SensoriamentoServoLogModel
|
|
{
|
|
public string ID { get; set; }
|
|
public int ID_Num { get; set; }
|
|
public string Descricao { get; set; }
|
|
public S_Code Componente { get; set; }
|
|
|
|
public bool Controlar { get; set; }
|
|
public bool Mandatorio { get; set; }
|
|
public bool Inicializado { get; set; }
|
|
public bool Liberado { get; set; }
|
|
public bool Incremental { get; set; }
|
|
|
|
public int AnguloNeutro { get; set; }
|
|
public int AnguloControle { get; set; }
|
|
public int AnguloLeitura { get; set; }
|
|
public double UltimoAnguloDesejado { get; set; }
|
|
|
|
public double ErroAngulo { get; set; }
|
|
public double ErroAnguloAbs { get; set; }
|
|
public bool Divergente { get; set; }
|
|
|
|
public DateTime UltimaLeitura { get; set; } = DateTime.MinValue;
|
|
public DateTime UltimoComandoEnviado { get; set; } = DateTime.MinValue;
|
|
public double IdadeUltimaLeituraMs { get; set; }
|
|
|
|
public List<SensoriamentoLeituraLogModel> Leituras { get; set; } = new List<SensoriamentoLeituraLogModel>();
|
|
|
|
public SensoriamentoServoLogModel Clone()
|
|
{
|
|
return new SensoriamentoServoLogModel
|
|
{
|
|
ID = ID,
|
|
ID_Num = ID_Num,
|
|
Descricao = Descricao,
|
|
Componente = Componente,
|
|
|
|
Controlar = Controlar,
|
|
Mandatorio = Mandatorio,
|
|
Inicializado = Inicializado,
|
|
Liberado = Liberado,
|
|
Incremental = Incremental,
|
|
|
|
AnguloNeutro = AnguloNeutro,
|
|
AnguloControle = AnguloControle,
|
|
AnguloLeitura = AnguloLeitura,
|
|
UltimoAnguloDesejado = UltimoAnguloDesejado,
|
|
|
|
ErroAngulo = ErroAngulo,
|
|
ErroAnguloAbs = ErroAnguloAbs,
|
|
Divergente = Divergente,
|
|
|
|
UltimaLeitura = UltimaLeitura,
|
|
UltimoComandoEnviado = UltimoComandoEnviado,
|
|
IdadeUltimaLeituraMs = IdadeUltimaLeituraMs,
|
|
|
|
Leituras = Leituras?.Select(x => x.Clone()).ToList() ?? new List<SensoriamentoLeituraLogModel>()
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
public class OperacaoSensoriamentoLogErrosModel
|
|
{
|
|
public DateTime Momento { get; set; }
|
|
public T_Code Dispositivo { get; set; }
|
|
public string ID { get; set; }
|
|
public StatusModulo Status { get; set; }
|
|
public double Saude { get; set; }
|
|
public string Mensagem { get; set; }
|
|
public string Condicoes { get; set; }
|
|
}
|
|
|
|
}
|