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

227 lines
8.5 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;
namespace AgroBase.Services.Operadores
{
public class WeedWorkerService : IWorkerModel
{
public static WeedWorkerModel DadosLeitura = new WeedWorkerModel();
public SaudeWorkerModel Saude { get; set; } = new SaudeWorkerModel();
public AsyncTaskTimerModel tmrPooling;
private bool DebugMode = true;
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;
tmrPooling?.Dispose();
tmrPooling = new AsyncTaskTimerModel("tmrWeedWorkerPooling", tmrPooling_Tick, 500);
tmrPooling.Start();
bool pronto() => DadosLeitura.Pronto;
await FuncoesGlobais.AguardarCondicaoAsync(pronto, 5000);
if (pronto())
{
MostrarLog("Processamento iniciado com sucesso");
return true;
}
MostrarLog("Timeout ao iniciar script");
DadosLeitura.ReiniciarEstado();
return false;
}
private async Task tmrPooling_Tick()
{
if (Variaveis.OperacaoEmAndamento.Controle.PulverizadorAutomatico)
{
var dictParams = RedisService.GetField<Dictionary<string, object>>(CtxKey.DadosControle, "controle_bicos");
AtualizarControle(dictParams);
}
}
private void AtualizarControle(Dictionary<string, object> dictParams)
{
if (dictParams == null)
return;
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);
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
foreach (var bico in _Controle.BicosAtuados)
{
novoComando.TryGetValue(bico.Posicao, out bool atuado);
bico.ComandoAtuar = atuado;
}
Variaveis.OperacaoEmAndamento.AtualizaInformacoesControleOperacao();
}
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:
CameraFrameType tipo = (CameraFrameType)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.Controle.PulverizadorAutomatico)
{
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(CameraFrameType tipo = CameraFrameType.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<CameraFrameType> 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()
{
var json = RedisService.Get(CtxKey.DadosWeedWorker);
var dados = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
if (dados.ContainsKey("ts_analise") && dados.ContainsKey("analise"))
{
var analise = JsonConvert.DeserializeObject<Dictionary<string, object>>(dados["analise"].ToString());
// 1. Timestamp (vem como double ou string)
DateTime timestamp = FuncoesGlobais.UnixToDateTime(analise["timestamp"].ToString());
// 2. Deteccoes (vem como List<object> ou string)
var listaDeteccoes = JsonConvert.DeserializeObject<List<WeedWorkerAnaliseDeteccaoModel>>(
analise["deteccoes"].ToString()
);
// 3. Controle: pode vir como Dictionary<string, object>
var controleDict = JsonConvert.DeserializeObject<Dictionary<string, bool>>(
analise["controle"].ToString()
);
var ervasIdentificadas = JsonConvert.DeserializeObject<List<Dictionary<string, int>>>(
analise["ervas_identificadas"].ToString()
);
// 4. Monta o objeto manualmente
var analiseObj = new WeedWorkerAnaliseModel
{
timestamp = timestamp,
frame_height = Convert.ToInt32(analise["frame_height"].ToString()),
frame_width = Convert.ToInt32(analise["frame_width"].ToString()),
deteccoes = listaDeteccoes,
controle = controleDict.ToDictionary(x => Convert.ToInt32(x.Key), x => x.Value),
ervas_identificadas = ervasIdentificadas
};
Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BicosPulverizadores?.ForEach(bico =>
{
int atuacoes = 0;
var ervas = DadosLeitura?.Analise?.ervas_identificadas ?? new List<Dictionary<string, int>>();
if (ervas.Count < bico.Posicao || bico.Posicao <= 0)
atuacoes = 0;
else
atuacoes = ervas[bico.Posicao - 1]?.Sum(x => x.Value) ?? 0;
bico.Atuacoes = atuacoes;
});
DadosLeitura.Analise = analiseObj;
}
}
}
}