agrobot_base/AgroBase/AgroBase/Services/Operadores/WeedWorkerService.cs

316 lines
11 KiB
C#

using AgroBase.Models.Operadores;
using AgroBase.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using static AgroBase.Models.Operadores.OperadoresModels;
using Newtonsoft.Json.Linq;
using static AgroBase.Models.Enums;
namespace AgroBase.Services.Operadores
{
public class WeedWorkerService : IWorkerModel
{
public static WeedWorkerModel DadosLeitura = new WeedWorkerModel();
public SaudeWorkerModel Saude { get; set; } = new SaudeWorkerModel();
private bool DebugMode = false;
private static double _lastTsAnaliseWeed = -1;
private static double _lastTsPerformanceWeed = -1;
public void MostrarLog(string message, int limite = 500)
{
if (DebugMode)
{
Console.WriteLine($"[WeedWorker] {message.Substring(0, Math.Min(limite, message.Length))}{(message.Length > limite ? "..." : "")}");
}
}
public async Task<bool> IniciarProcessamento()
{
RedisService.Subscribe(CmdKey.WeedWorkerTx, RedisCallback);
DadosLeitura.IniciadoEm = DateTime.Now;
DadosLeitura.Iniciado = true;
bool pronto() => DadosLeitura.Pronto;
await FuncoesGlobais.AguardarCondicaoAsync(pronto, VariaveisOperacao.Operadores.TimeoutIniciarWorkerMs);
if (pronto())
{
MostrarLog("Processamento iniciado com sucesso");
return true;
}
MostrarLog("Timeout ao iniciar script");
DadosLeitura.ReiniciarEstado();
return false;
}
private void AtualizarControle(Dictionary<string, object> dictParams)
{
if (dictParams == null)
return;
var op = Variaveis.OperacaoEmAndamento;
var novoComando = dictParams
.Select(kv => new
{
Key = int.TryParse(kv.Key, out var i) ? (i + 1) : -1,
Value = Convert.ToBoolean(kv.Value)
})
.Where(x => x.Key >= 0)
.ToDictionary(x => x.Key, x => x.Value);
bool comandoMudou = false;
var _Controle = op.Controle;
foreach (var bico in _Controle.Bicos ?? new List<Models.Modules.AtuadorBicoModel>())
{
novoComando.TryGetValue(bico.Posicao, out bool atuado);
if (!(op.DispAtu?.Dados?.ContadorCarga?.PulverizadorLiberado ?? false)) atuado = false;
if (!comandoMudou) comandoMudou = atuado != bico.ComandoAtuar;
bico.ComandoAtuar = atuado;
}
if (comandoMudou)
{
Variaveis.MostrarLog("[WeedWorkerService] [AtualizarControle] Comando dos bicos alterado: " + JsonConvert.SerializeObject(novoComando));
var pControle = op.Parametros.Controle;
if (pControle.PulverizadorAutomatico)
{
op.AtualizarDadosControle(false, new List<T_Code>() { T_Code.Atu });
}
}
}
public void RedisCallback(string mensagem)
{
try
{
var comando = JsonConvert.DeserializeObject<ComandoRedis>(mensagem);
var cmd = (WeedWorkerCommandType)comando.cmd;
//MostrarLog($"Comando recebido: cmd = {cmd.ToString()}");
switch (cmd)
{
case WeedWorkerCommandType.ScriptCarregado:
DadosLeitura.Pronto = true;
DadosLeitura.ProntoEm = DateTime.Now;
MostrarLog($"Comando recebido: cmd = {cmd.ToString()}");
break;
case WeedWorkerCommandType.GetCameraFrame:
TipoFrameCamera tipo = (TipoFrameCamera)Convert.ToInt32(comando.@params["tipo"].ToString());
DadosLeitura.CameraFrames[tipo] = new OAKCameraFrameModel()
{
frame = comando.@params["frame"].ToString(),
timestamp = FuncoesGlobais.UnixToDateTime(comando.@params["timestamp"].ToString()),
};
break;
case WeedWorkerCommandType.EnviarDadosControle:
if (Variaveis.OperacaoEmAndamento.Parametros.Controle?.PulverizadorAutomatico ?? false)
{
AtualizarControle(comando.@params);
}
break;
default:
MostrarLog($"Comando não reconhecido: {comando.cmd}");
break;
}
}
catch (Exception ex)
{
MostrarLog($"Erro ao deserializar resposta: {ex.Message}");
}
finally
{
DadosLeitura.UltimaMensagem = DateTime.Now;
}
}
public void AtualizarSaude()
{
Saude = OperadoresModels.AtualizarSaude(CtxKey.DadosWeedWorker);
}
public static async Task<OAKCameraFrameModel> GetCameraFrame(TipoFrameCamera tipo = TipoFrameCamera.Rgb)
{
DateTime Inicio = DateTime.Now;
var comando = new
{
cmd = WeedWorkerCommandType.GetCameraFrame,
@params = tipo,
};
RedisService.Publish(CmdKey.WeedWorkerRx, JsonConvert.SerializeObject(comando));
bool Frame() => DadosLeitura.CameraFrames.TryGetValue(tipo, out var frame) && (frame?.timestamp ?? DateTime.MinValue) > Inicio;
await FuncoesGlobais.AguardarCondicaoAsync(Frame, 1000, 100);
DadosLeitura.CameraFrames.TryGetValue(tipo, out OAKCameraFrameModel _frame);
return _frame;
}
public static void SaveCameraFrames(List<TipoFrameCamera> frames, string nome, string caminho)
{
var comando = new
{
cmd = WeedWorkerCommandType.SaveCameraFrames,
@params = new
{
nome = nome,
caminho = caminho,
tipos = frames.Select(x => (int)x).ToArray(),
},
};
RedisService.Publish(CmdKey.WeedWorkerRx, JsonConvert.SerializeObject(comando));
}
public static void AtualizarAnalise()
{
AtualizarImu();
string json = RedisService.Get(CtxKey.DadosWeedWorker);
if (string.IsNullOrWhiteSpace(json))
return;
JObject root;
try
{
root = JObject.Parse(json);
}
catch (Exception ex)
{
Variaveis.MostrarLog($"[WeedWorkerService.AtualizarAnalise] Erro ao interpretar DadosWeedWorker: {ex.Message}");
return;
}
double tsAnalise = root["ts_analise"]?.Value<double>() ?? 0.0;
double tsAnaliseWeed = root["ts_analise_weed"]?.Value<double>() ?? 0.0;
double tsPerformance = root["ts_performance_weed"]?.Value<double>() ?? 0.0;
DadosLeitura.Timestamps.analise = tsAnalise;
DadosLeitura.Timestamps.analise_weed = tsAnaliseWeed;
DadosLeitura.Timestamps.performance_weed = tsPerformance;
if (tsAnaliseWeed > 0 && tsAnaliseWeed != _lastTsAnaliseWeed)
{
JToken envelopeToken = root["analise"];
if (envelopeToken != null && envelopeToken.Type != JTokenType.Null)
{
try
{
var envelope = envelopeToken.ToObject<WeedWorkerAnaliseEnvelopeModel>();
if (envelope != null)
{
DadosLeitura.MetricasAnalise =
new WeedWorkerAnaliseMetricasModel
{
ts_analise = envelope.ts_analise,
fps_model = envelope.fps_model,
fps_inferencia = envelope.fps_inferencia,
infer_ms = envelope.infer_ms,
infer_gpu_ms = envelope.infer_gpu_ms
};
DadosLeitura.Analise = envelope.analise ?? new WeedWorkerAnaliseModel();
}
}
catch (Exception ex)
{
Variaveis.MostrarLog($"[WeedWorkerService.AtualizarAnalise] Erro ao desserializar análise de ervas: {ex.Message}");
}
}
_lastTsAnaliseWeed = tsAnaliseWeed;
}
if (tsPerformance > 0 && tsPerformance != _lastTsPerformanceWeed)
{
JToken performanceToken = root["performance_weed"];
if (performanceToken != null && performanceToken.Type != JTokenType.Null)
{
try
{
var performance = performanceToken.ToObject<WeedWorkerPerformanceModel>();
if (performance != null)
{
performance.timestamp = tsPerformance;
DadosLeitura.Performance = performance;
}
}
catch (Exception ex)
{
Variaveis.MostrarLog($"[WeedWorkerService.AtualizarAnalise] Erro ao desserializar performance weed: {ex.Message}");
}
}
_lastTsPerformanceWeed = tsPerformance;
}
}
private static void AtualizarImu()
{
try
{
string mxId = VariaveisEquipamento.Parametros.camera_ervas_id.FirstOrDefault();
if (string.IsNullOrWhiteSpace(mxId))
return;
string cameraJson = RedisService.Get(RedisService.CamKey(mxId));
if (string.IsNullOrWhiteSpace(cameraJson))
return;
JObject root = JObject.Parse(cameraJson);
JToken imuToken = root["imu"];
if (imuToken == null || imuToken.Type == JTokenType.Null)
return;
var imu = imuToken.ToObject<OAKImuModel>();
if (imu != null)
DadosLeitura.Imu = imu;
}
catch
{
// Mantém a última leitura válida.
}
}
public static void ReiniciarLeituraAnalise()
{
RedisService.AtualizarCampos(
CtxKey.DadosWeedWorker,
("analise.analise.ervas_no_radar", false),
("analise.analise.controle", new Dictionary<string, bool>(Variaveis.OperacaoEmAndamento.DispAtu.Dados.BicosPulverizadores.ToDictionary(x => x.Posicao.ToString(), x => false))),
("analise.analise.estatisticas", new WeedWorkerAnaliseEstatisticasModel()),
("ts_analise_weed", 0.0)
);
_lastTsAnaliseWeed = -1;
DadosLeitura.Analise = new WeedWorkerAnaliseModel();
DadosLeitura.MetricasAnalise = new WeedWorkerAnaliseMetricasModel();
}
}
}