iniciado comunicacao ip mqtt

This commit is contained in:
Diego Freitas 2025-11-06 13:18:32 -03:00
parent a6acd81d17
commit ba51fa73ca
29 changed files with 468 additions and 79 deletions

Binary file not shown.

View File

@ -47,7 +47,7 @@ namespace AgroBase.Forms
try try
{ {
cameraSolo.camera.pythonProcess?.Kill(); cameraSolo.camera.pythonProcess?.Kill();
Variaveis.MqttService.UnsubscribeAsync(cameraSolo.camera._mqttTopico).ConfigureAwait(false); Variaveis.MqttServiceLocal.UnsubscribeAsync(cameraSolo.camera._mqttTopico).ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -183,7 +183,7 @@ namespace AgroBase.Forms
int i = 0; int i = 0;
//var coordenadas = cameraService.AferirDadosCamera<CameraCoordenadasModel>(); //var coordenadas = cameraService.AferirDadosCamera<CameraCoordenadasModel>();
var MqttTopico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == cameraSolo.MqttTopico); var MqttTopico = Variaveis.MqttServiceLocal.Topicos.FirstOrDefault(x => x.Topico == cameraSolo.MqttTopico);
if (MqttTopico == null) if (MqttTopico == null)
{ {

View File

@ -302,7 +302,7 @@ namespace AgroBase.Forms.IHM
} }
} }
bool mqttConectado = Variaveis.MqttService.StatusConexao(); bool mqttConectado = Variaveis.MqttServiceLocal.StatusConexao();
lblMqtt.Text = "MQTT: " + (mqttConectado ? "Conectado" : "Desconectado"); lblMqtt.Text = "MQTT: " + (mqttConectado ? "Conectado" : "Desconectado");
lblMqtt.ForeColor = mqttConectado ? Color.Green : Color.Red; lblMqtt.ForeColor = mqttConectado ? Color.Green : Color.Red;

View File

@ -65,7 +65,7 @@ namespace AgroBase.Forms.Movimentacao
try try
{ {
tmrLeitura.Stop(); tmrLeitura.Stop();
Variaveis.MqttService.UnsubscribeAsync(cameraService._mqttTopico).GetAwaiter().GetResult(); Variaveis.MqttServiceLocal.UnsubscribeAsync(cameraService._mqttTopico).GetAwaiter().GetResult();
cameraService.pythonProcess.Kill(); cameraService.pythonProcess.Kill();
} }
catch (Exception ex) catch (Exception ex)

View File

@ -34,7 +34,7 @@ namespace AgroBase.Forms.Sensoriamento
{ {
try try
{ {
Variaveis.MqttService.UnsubscribeAsync(cameraService._mqttTopico).GetAwaiter().GetResult(); Variaveis.MqttServiceLocal.UnsubscribeAsync(cameraService._mqttTopico).GetAwaiter().GetResult();
cameraService.pythonProcess?.Kill(); cameraService.pythonProcess?.Kill();
} }
catch (Exception ex) catch (Exception ex)
@ -119,7 +119,7 @@ namespace AgroBase.Forms.Sensoriamento
this.pnlLeituras.Controls.Clear(); this.pnlLeituras.Controls.Clear();
int i = 0; int i = 0;
var MqttTopico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == VideoUrl); var MqttTopico = Variaveis.MqttServiceLocal.Topicos.FirstOrDefault(x => x.Topico == VideoUrl);
CameraCoordenadasFrameModel leitura = null; CameraCoordenadasFrameModel leitura = null;
var Mensagem = MqttTopico.Mensagens.LastOrDefault(x => x.Momento > cameraService.IniciadoEm); var Mensagem = MqttTopico.Mensagens.LastOrDefault(x => x.Momento > cameraService.IniciadoEm);
if (Mensagem != null) if (Mensagem != null)

View File

@ -57,8 +57,8 @@ namespace AgroBase.Forms
ReiniciarModelo(); ReiniciarModelo();
await Variaveis.MqttService.AdicionarNovoTopico(mqtt_topico_state); await Variaveis.MqttServiceLocal.AdicionarNovoTopico(mqtt_topico_state);
await Variaveis.MqttService.AdicionarNovoTopico(mqtt_topico_action, true, 2, async (message) => await Variaveis.MqttServiceLocal.AdicionarNovoTopico(mqtt_topico_action, true, 2, async (message) =>
{ {
Console.WriteLine("Mensagem recebida pelo modelo de IA: " + message); Console.WriteLine("Mensagem recebida pelo modelo de IA: " + message);
//btnAcrescentarGPS_Click(new Button(), new EventArgs()); //btnAcrescentarGPS_Click(new Button(), new EventArgs());
@ -72,10 +72,10 @@ namespace AgroBase.Forms
private async void frmTreinamentoIA_FormClosing(object sender, FormClosingEventArgs e) private async void frmTreinamentoIA_FormClosing(object sender, FormClosingEventArgs e)
{ {
var t0 = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == mqtt_topico_state); var t0 = Variaveis.MqttServiceLocal.Topicos.FirstOrDefault(x => x.Topico == mqtt_topico_state);
await Variaveis.MqttService.UnsubscribeAsync(t0); await Variaveis.MqttServiceLocal.UnsubscribeAsync(t0);
var t1 = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == mqtt_topico_action); var t1 = Variaveis.MqttServiceLocal.Topicos.FirstOrDefault(x => x.Topico == mqtt_topico_action);
await Variaveis.MqttService.UnsubscribeAsync(t1); await Variaveis.MqttServiceLocal.UnsubscribeAsync(t1);
Variaveis.OperacaoEmAndamento.Treinando = false; Variaveis.OperacaoEmAndamento.Treinando = false;
} }
@ -481,8 +481,8 @@ namespace AgroBase.Forms
_robotState.UpdateCurrentRobotState(); _robotState.UpdateCurrentRobotState();
await Variaveis.MqttService.PublishAsync( await Variaveis.MqttServiceLocal.PublishAsync(
Variaveis.MqttService.Topicos.First(x => x.Topico == mqtt_topico_state), Variaveis.MqttServiceLocal.Topicos.First(x => x.Topico == mqtt_topico_state),
JsonConvert.SerializeObject(_robotState) JsonConvert.SerializeObject(_robotState)
); );
} }

View File

@ -27,6 +27,8 @@ namespace AgroBase.Forms
ThreadPool.SetMinThreads(workerThreads: 50, completionPortThreads: 50); ThreadPool.SetMinThreads(workerThreads: 50, completionPortThreads: 50);
Variaveis.IniciarMQTT();
APIService.IniciarRotinas(); APIService.IniciarRotinas();
GeneralJoystick.IniciarRotinas(); GeneralJoystick.IniciarRotinas();
@ -93,7 +95,7 @@ namespace AgroBase.Forms
private async void IniciarConexaoMqtt() private async void IniciarConexaoMqtt()
{ {
await Variaveis.MqttService.ConnectAsync(); await Variaveis.MqttServiceLocal.ConnectAsync();
} }
public static async Task EncerrarProcessos() public static async Task EncerrarProcessos()

View File

@ -98,7 +98,7 @@ namespace AgroBase
{ {
AtualizaDadosGerais(); AtualizaDadosGerais();
lblStripMqtt.Text = "MQTT: " + (Variaveis.MqttService.StatusConexao() ? "Conectado" : "Desconectado"); lblStripMqtt.Text = "MQTT: " + (Variaveis.MqttServiceLocal.StatusConexao() ? "Conectado" : "Desconectado");
lblStripPython.Text = "IA: " + (VariaveisOperacao.Operadores.Conectado ? "Conectado" : "Desconectado"); lblStripPython.Text = "IA: " + (VariaveisOperacao.Operadores.Conectado ? "Conectado" : "Desconectado");
lblStripPython.ForeColor = VariaveisOperacao.Operadores.Conectado ? Color.Green : Color.Red; lblStripPython.ForeColor = VariaveisOperacao.Operadores.Conectado ? Color.Green : Color.Red;

View File

@ -60,13 +60,13 @@ namespace AgroBase.Models
try try
{ {
Iniciada = false; Iniciada = false;
Variaveis.MqttService.Topicos.Remove(camera._mqttTopico); Variaveis.MqttServiceLocal.Topicos.Remove(camera._mqttTopico);
if (panelRgb != null) if (panelRgb != null)
{ {
panelRgb.Controls.Remove(browserRgb); panelRgb.Controls.Remove(browserRgb);
} }
browserRgb = null; browserRgb = null;
Task.Run(async () => await Variaveis.MqttService.UnsubscribeAsync(camera._mqttTopico)); Task.Run(async () => await Variaveis.MqttServiceLocal.UnsubscribeAsync(camera._mqttTopico));
lock (camera.processLock) lock (camera.processLock)
{ {

View File

@ -18,13 +18,13 @@ namespace AgroBase.Models
try try
{ {
Iniciada = false; Iniciada = false;
Variaveis.MqttService.Topicos.Remove(camera._mqttTopico); Variaveis.MqttServiceLocal.Topicos.Remove(camera._mqttTopico);
if (panel != null) if (panel != null)
{ {
panel.Controls.Remove(browser); panel.Controls.Remove(browser);
} }
browser = null; browser = null;
Task.Run(async () => await Variaveis.MqttService.UnsubscribeAsync(camera._mqttTopico)); Task.Run(async () => await Variaveis.MqttServiceLocal.UnsubscribeAsync(camera._mqttTopico));
lock (camera.processLock) lock (camera.processLock)
{ {
if (camera.pythonProcess != null) if (camera.pythonProcess != null)

View File

@ -29,9 +29,9 @@ public class MPCController
public async Task<bool> Inicializar() public async Task<bool> Inicializar()
{ {
await Variaveis.MqttService.AdicionarNovoTopico(TopicoRota); await Variaveis.MqttServiceLocal.AdicionarNovoTopico(TopicoRota);
await Variaveis.MqttService.AdicionarNovoTopico(TopicoPosicao); await Variaveis.MqttServiceLocal.AdicionarNovoTopico(TopicoPosicao);
await Variaveis.MqttService.AdicionarNovoTopico(TopicoComando, true, 2, async (mensagem) => await Variaveis.MqttServiceLocal.AdicionarNovoTopico(TopicoComando, true, 2, async (mensagem) =>
{ {
if (mensagem.Mensagem == "OK") if (mensagem.Mensagem == "OK")
{ {
@ -84,8 +84,8 @@ public class MPCController
velocidade_max = FuncoesMatematicas.CalculaVelocidadeMsPercentual(_Controle.PercentualVelocidadeMax) velocidade_max = FuncoesMatematicas.CalculaVelocidadeMsPercentual(_Controle.PercentualVelocidadeMax)
}; };
await Variaveis.MqttService.PublishAsync( await Variaveis.MqttServiceLocal.PublishAsync(
Variaveis.MqttService.Topicos.First(x => x.Topico == TopicoRota), Variaveis.MqttServiceLocal.Topicos.First(x => x.Topico == TopicoRota),
JsonConvert.SerializeObject(trajetoria) JsonConvert.SerializeObject(trajetoria)
); );
} }
@ -123,8 +123,8 @@ public class MPCController
} }
}; };
await Variaveis.MqttService.PublishAsync( await Variaveis.MqttServiceLocal.PublishAsync(
Variaveis.MqttService.Topicos.First(x => x.Topico == TopicoPosicao), Variaveis.MqttServiceLocal.Topicos.First(x => x.Topico == TopicoPosicao),
JsonConvert.SerializeObject(dadosEnvio) JsonConvert.SerializeObject(dadosEnvio)
); );
@ -161,10 +161,10 @@ public class MPCController
Iniciado = false; Iniciado = false;
ComandoAtual = new MPCComandoModel(); ComandoAtual = new MPCComandoModel();
Task.Run(async () => { Task.Run(async () => {
Variaveis.MqttService.Topicos.Remove(Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == TopicoRota)); Variaveis.MqttServiceLocal.Topicos.Remove(Variaveis.MqttServiceLocal.Topicos.FirstOrDefault(x => x.Topico == TopicoRota));
Variaveis.MqttService.Topicos.Remove(Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == TopicoPosicao)); Variaveis.MqttServiceLocal.Topicos.Remove(Variaveis.MqttServiceLocal.Topicos.FirstOrDefault(x => x.Topico == TopicoPosicao));
await Variaveis.MqttService.UnsubscribeAsync(Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == TopicoComando)); await Variaveis.MqttServiceLocal.UnsubscribeAsync(Variaveis.MqttServiceLocal.Topicos.FirstOrDefault(x => x.Topico == TopicoComando));
Variaveis.MqttService.Topicos.Remove(Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == TopicoComando)); Variaveis.MqttServiceLocal.Topicos.Remove(Variaveis.MqttServiceLocal.Topicos.FirstOrDefault(x => x.Topico == TopicoComando));
}); });
} }

View File

@ -28,7 +28,7 @@ namespace AgroBase.Models
public void btnCarregar_Click(object sender, EventArgs e, string caminhoArquivo = "", bool monitoramento = false) public void btnCarregar_Click(object sender, EventArgs e, string caminhoArquivo = "", bool monitoramento = false)
{ {
var Topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == MapasVariaveisModel.TopicoSelecaoRuasMapa); var Topico = Variaveis.MqttServiceLocal.Topicos.FirstOrDefault(x => x.Topico == MapasVariaveisModel.TopicoSelecaoRuasMapa);
Topico.Mensagens.Clear(); Topico.Mensagens.Clear();
TipoMapaOperacao? _tipoMapa = TipoMapa; TipoMapaOperacao? _tipoMapa = TipoMapa;
@ -234,7 +234,7 @@ namespace AgroBase.Models
{ {
List<string> ids = new List<string>(); List<string> ids = new List<string>();
bool idsMensagem = false; bool idsMensagem = false;
var Topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == MapasVariaveisModel.TopicoSelecaoRuasMapa); var Topico = Variaveis.MqttServiceLocal.Topicos.FirstOrDefault(x => x.Topico == MapasVariaveisModel.TopicoSelecaoRuasMapa);
var Mensagem = Topico.Mensagens.LastOrDefault(); var Mensagem = Topico.Mensagens.LastOrDefault();
if (Mensagem != null && !Mensagem.Mensagem.Contains("[]")) if (Mensagem != null && !Mensagem.Mensagem.Contains("[]"))
{ {

View File

@ -16,6 +16,7 @@ using System.Text;
using static AgroBase.Services.OIDCanService.OidHandler; using static AgroBase.Services.OIDCanService.OidHandler;
using AgroBase.Models.Operadores; using AgroBase.Models.Operadores;
using AgroBase.Services.Operadores; using AgroBase.Services.Operadores;
using AgroMonitor;
namespace AgroBase.Models namespace AgroBase.Models
{ {
@ -34,6 +35,10 @@ namespace AgroBase.Models
tmrLeituras?.Dispose(); tmrLeituras?.Dispose();
tmrLeituras = new AsyncTaskTimerModel("tmrLeitura", tmrLeituras_Tick, 500); tmrLeituras = new AsyncTaskTimerModel("tmrLeitura", tmrLeituras_Tick, 500);
tmrLeituras.Start(); tmrLeituras.Start();
tmrComunicacao?.Dispose();
tmrComunicacao = new AsyncTaskTimerModel("tmrComunicacao", tmrComunicacao_Tick, 1000);
tmrComunicacao.Start();
} }
} }
@ -141,6 +146,7 @@ namespace AgroBase.Models
} }
} }
private static AsyncTaskTimerModel tmrLeituras; private static AsyncTaskTimerModel tmrLeituras;
private static AsyncTaskTimerModel tmrComunicacao;
@ -924,7 +930,7 @@ namespace AgroBase.Models
Variaveis.OperacaoEmAndamento.Trajetoria = new TrajetoriaMapaOperacaoModel(new List<List<GPSModel>>()); Variaveis.OperacaoEmAndamento.Trajetoria = new TrajetoriaMapaOperacaoModel(new List<List<GPSModel>>());
Variaveis.OperacaoEmAndamento.GPSTrajetoria = new List<GPSModel>(); Variaveis.OperacaoEmAndamento.GPSTrajetoria = new List<GPSModel>();
var Topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == MapasVariaveisModel.TopicoSelecaoRuasMapa); var Topico = Variaveis.MqttServiceLocal.Topicos.FirstOrDefault(x => x.Topico == MapasVariaveisModel.TopicoSelecaoRuasMapa);
Topico.Mensagens.Add(new MqttService.MqttTopicosMensagensModel() Topico.Mensagens.Add(new MqttService.MqttTopicosMensagensModel()
{ {
Mensagem = "[]", Mensagem = "[]",
@ -1186,7 +1192,7 @@ namespace AgroBase.Models
} }
Variaveis.OperacaoEmAndamento.Sensoriamento.AtualizarDados(); Variaveis.OperacaoEmAndamento.Sensoriamento.AtualizarDados();
Variaveis.LoraService?.EnviarDadosParaBase(); //Variaveis.LoraService?.EnviarDadosParaBase();
if (!Variaveis.OperacaoEmAndamento.Iniciado) if (!Variaveis.OperacaoEmAndamento.Iniciado)
{ {
@ -1240,6 +1246,27 @@ namespace AgroBase.Models
_Controle.TipoMovimento = oldTipoMovimento; _Controle.TipoMovimento = oldTipoMovimento;
} }
private async Task tmrComunicacao_Tick()
{
bool base_encontrada = (DateTime.Now - VariaveisOperacao.PosicaoBase.Momento).TotalSeconds < 10;
MqttService.MqttTopicosModel topico = null;
string msg = string.Empty;
if (!base_encontrada)
{
topico = Variaveis.MqttServiceBase.Topicos.FirstOrDefault(x => x.Topico == VariaveisMonitoramento.TopicoMqttDispositivos);
msg = VariaveisEquipamento.Parametros.serial_number;
}
else
{
topico = Variaveis.MqttServiceBase.Topicos.FirstOrDefault(x => x.Topico == VariaveisEquipamento.TopicoMqttTelemetria.Replace("<id>", VariaveisEquipamento.Parametros.serial_number));
msg = JsonConvert.SerializeObject(Variaveis.OperacaoEmAndamento.Sensoriamento);
}
if (topico != null && !string.IsNullOrEmpty(msg))
{
await Variaveis.MqttServiceBase.PublishAsync(topico, msg);
}
}
#endregion #endregion
#region REGISTRO DE LOGS #region REGISTRO DE LOGS

View File

@ -16,9 +16,10 @@ using System.Threading;
using AgroBase.Models.Components; using AgroBase.Models.Components;
using Microsoft.Web.WebView2.WinForms; using Microsoft.Web.WebView2.WinForms;
using Microsoft.Web.WebView2.Core; using Microsoft.Web.WebView2.Core;
using System.Text.Json;
using AgroBase.Services.Operadores; using AgroBase.Services.Operadores;
using System.Diagnostics; using System.Diagnostics;
using Newtonsoft.Json;
using AgroMonitor;
namespace AgroBase.Models namespace AgroBase.Models
{ {
@ -55,7 +56,8 @@ namespace AgroBase.Models
public static string CaminhoModelos { get; } = "C:\\AgroBaseModels\\"; public static string CaminhoModelos { get; } = "C:\\AgroBaseModels\\";
public static List<IDispositivosService> DispositivosConectados { get; set; } = new List<IDispositivosService>(); public static List<IDispositivosService> DispositivosConectados { get; set; } = new List<IDispositivosService>();
public static OperacaoModel OperacaoEmAndamento { get; set; } = new OperacaoModel(ModoOperacao.Manual); public static OperacaoModel OperacaoEmAndamento { get; set; } = new OperacaoModel(ModoOperacao.Manual);
public static MqttService MqttService { get; set; } = new MqttService("localhost", 1883); public static MqttService MqttServiceLocal { get; set; }
public static MqttService MqttServiceBase { get; set; }
public static LoRaEspService LoraService public static LoRaEspService LoraService
{ {
get get
@ -86,6 +88,105 @@ namespace AgroBase.Models
public static byte ID_Num_sMOD { get; } = 0; public static byte ID_Num_sMOD { get; } = 0;
public static byte ID_Num_sTOD { get; } = 250; public static byte ID_Num_sTOD { get; } = 250;
public static byte ID_Num_sLRA { get; } = 251; public static byte ID_Num_sLRA { get; } = 251;
public static async void IniciarMQTT()
{
if (MqttServiceLocal != null)
{
foreach (var topico in MqttServiceLocal.Topicos.Where(x => x.Inscrever))
{
await MqttServiceLocal.UnsubscribeAsync(topico);
}
MqttServiceLocal.Topicos.Clear();
}
if (MqttServiceBase != null && !IsAgroMonitor)
{
foreach (var topico in MqttServiceBase.Topicos.Where(x => x.Inscrever))
{
await MqttServiceBase.UnsubscribeAsync(topico);
}
MqttServiceBase.Topicos.Clear();
}
MqttServiceLocal = new MqttService("localhost", 1883, IsAgroMonitor ? "base" : VariaveisEquipamento.Parametros.serial_number, true);
await MqttServiceLocal.AdicionarNovoTopico(MapasVariaveisModel.TopicoCoordenadasGPS);
await MqttServiceLocal.AdicionarNovoTopico(MapasVariaveisModel.TopicoTrajetoriaDinamica);
await MqttServiceLocal.AdicionarNovoTopico(MapasVariaveisModel.TopicoSelecaoRuasMapa, true, 1, async (message) =>
{
OperacaoEmAndamento.Mapa.AtualizarRuasSelecionadas();
});
if (IsAgroMonitor)
{
await MqttServiceLocal.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttRTCM);
await MqttServiceLocal.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttDispositivos, true, 1, async (message) =>
{
try
{
string device_id = message.Mensagem;
VariaveisMonitoramento.AdicionarNovoRoverNaRede(message.Mensagem);
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao deserializar ping do rover: {ex.Message}");
}
});
}
else
{
MqttServiceBase = new MqttService(VariaveisEquipamento.Parametros.base_ip, 1883, VariaveisEquipamento.Parametros.serial_number, false);
await MqttServiceBase.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttDispositivos);
await MqttServiceBase.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttTelemetria.Replace("<id>", VariaveisEquipamento.Parametros.serial_number));
await MqttServiceBase.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttComandos.Replace("<id>", VariaveisEquipamento.Parametros.serial_number), true, 1, async (message) =>
{
if (string.IsNullOrEmpty(message.Mensagem))
return;
try
{
string json = message.Mensagem;
var cmd = JsonConvert.DeserializeObject<OperacaoControleBaseModel>(json);
OperacaoEmAndamento.ExecutaComandoDaBase(cmd);
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao deserializar comando da base: {ex.Message}");
}
});
await MqttServiceBase.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttRTCM, true, 1, async (message) =>
{
if (message.Bytes == null || message.Bytes.Length == 0)
return;
try
{
var bytes = message.Bytes;
if (bytes != null && bytes.Length > 0)
{
GPSService.AplicarCorrecaoRTK_Mqtt(bytes, bytes.Length);
}
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao deserializar RTCM da base: {ex.Message}");
}
});
await MqttServiceBase.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttPosicao, true, 1, async (message) =>
{
if (string.IsNullOrEmpty(message.Mensagem))
return;
try
{
string json = message.Mensagem;
var posicao = JsonConvert.DeserializeObject<GPSModel>(json);
VariaveisOperacao.PosicaoBase = posicao;
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao deserializar dados da base: {ex.Message}");
}
});
}
}
} }
public static class VariaveisPortas public static class VariaveisPortas
@ -98,6 +199,25 @@ namespace AgroBase.Models
public static class VariaveisEquipamento public static class VariaveisEquipamento
{ {
private static ParametrosConfigEquipamentoModel _parametros;
public static ParametrosConfigEquipamentoModel Parametros
{
get
{
if (_parametros == null)
{
_parametros = new ParametrosConfigEquipamentoModel();
_parametros.AtualizarParametros();
}
return _parametros;
}
set
{
_parametros = value;
}
}
public static string TopicoMqttComandos { get; } = $"agrobot/v1/rover/<id>/cmd";
public static string TopicoMqttTelemetria { get; } = $"agrobot/v1/rover/<id>/telemetry";
public static double LarguraEsquerda { get; } = 44.0; // 62 public static double LarguraEsquerda { get; } = 44.0; // 62
public static double LarguraDireita { get; } = 44.0; // 22 public static double LarguraDireita { get; } = 44.0; // 22
public static double ComprimentoFrente { get; } = 7.0; // 7 public static double ComprimentoFrente { get; } = 7.0; // 7
@ -191,6 +311,8 @@ namespace AgroBase.Models
public static double AnguloInclinacaoPitchMax { get; set; } = 45.0; public static double AnguloInclinacaoPitchMax { get; set; } = 45.0;
public static string VozAlerta { get; set; } = "Microsoft Maria Desktop"; public static string VozAlerta { get; set; } = "Microsoft Maria Desktop";
public static SensorSinaleiroComportamentoModel ComportamentoLedPorStatus(StatusOperacao? _status = null) public static SensorSinaleiroComportamentoModel ComportamentoLedPorStatus(StatusOperacao? _status = null)
{ {
if (_status == null) if (_status == null)
@ -444,6 +566,38 @@ namespace AgroBase.Models
return novaPosicao; return novaPosicao;
} }
public class ParametrosConfigEquipamentoModel
{
public bool Carregado { get; set; }
public string serial_number { get; set; }
public string base_ip { get; set; }
public void AtualizarParametros()
{
string config_path = Path.Combine(Variaveis.CaminhoSistema, Variaveis.CaminhoParametros, "config.json");
if (!File.Exists(config_path))
Carregado = false;
try
{
string json = File.ReadAllText(config_path);
var par = JsonConvert.DeserializeObject<ParametrosConfigEquipamentoModel>(json);
serial_number = par.serial_number;
base_ip = par.base_ip;
Carregado = true;
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao carregar arquivo de configuracoes: {ex.Message}");
Carregado = false;
}
}
}
} }
public static class VariaveisOperacao public static class VariaveisOperacao
@ -1252,7 +1406,7 @@ namespace AgroBase.Models
string result = await browser.CoreWebView2.ExecuteScriptAsync(script); string result = await browser.CoreWebView2.ExecuteScriptAsync(script);
// O resultado vem como string JSON (ex: "\"Texto dentro do body\"") // O resultado vem como string JSON (ex: "\"Texto dentro do body\"")
string conteudo = JsonSerializer.Deserialize<string>(result); string conteudo = System.Text.Json.JsonSerializer.Deserialize<string>(result);
if (string.IsNullOrWhiteSpace(conteudo) || if (string.IsNullOrWhiteSpace(conteudo) ||
conteudo.Contains("Internal Server Error") || conteudo.Contains("Internal Server Error") ||

View File

@ -1,5 +1,6 @@
using AgroBase.Models; using AgroBase.Models;
using AgroBase.Services; using AgroBase.Services;
using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -121,5 +122,78 @@ namespace AgroMonitor
public static double LeverArmFrontal { get; } = 0.0; public static double LeverArmFrontal { get; } = 0.0;
public static double LeverArmLateral { get; } = 0.0; public static double LeverArmLateral { get; } = 0.0;
public static string TopicoMqttDispositivos { get; } = $"agrobot/v1/base/devices";
public static string TopicoMqttPosicao { get; } = $"agrobot/v1/base/position";
public static string TopicoMqttRTCM { get; } = $"agrobot/v1/base/rtcm";
private static readonly object _RoversLock = new object();
public static Dictionary<string, OperacaoSensoriamentoLogModel> RoversNaRede { get; set; } = new Dictionary<string, OperacaoSensoriamentoLogModel>();
public static async void AdicionarNovoRoverNaRede(string device_id)
{
if (string.IsNullOrEmpty(device_id))
return;
bool rover_ja_adicionado = false;
lock (_RoversLock)
{
rover_ja_adicionado = RoversNaRede.ContainsKey(device_id);
}
if (!rover_ja_adicionado)
{
lock (_RoversLock)
{
RoversNaRede.Add(device_id, new OperacaoSensoriamentoLogModel() { Momento = DateTime.Now });
}
await Variaveis.MqttServiceLocal.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttComandos.Replace("<id>", device_id));
await Variaveis.MqttServiceLocal.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttTelemetria.Replace("<id>", device_id), true, 1, async (message) =>
{
try
{
string json = message.Mensagem;
var obj = JsonConvert.DeserializeObject<OperacaoSensoriamentoLogModel>(json);
lock (_RoversLock)
{
RoversNaRede[device_id] = obj;
}
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao deserializar dados de telemetria do rover {device_id}: {ex.Message}");
}
});
}
}
public static async void AtualizarListaRoversNaRede()
{
List<string> rovers_desconectados = new List<string>();
var rovers_atual = new Dictionary<string, OperacaoSensoriamentoLogModel>();
lock (_RoversLock)
{
rovers_atual = new Dictionary<string, OperacaoSensoriamentoLogModel>(RoversNaRede);
}
foreach (var rover in rovers_atual)
{
double tempo_sem_resposta = (DateTime.Now - rover.Value.Momento).TotalSeconds;
if (tempo_sem_resposta > 5.0)
{
rovers_desconectados.Add(rover.Key);
}
}
foreach (var device_id in rovers_desconectados)
{
lock (_RoversLock)
{
RoversNaRede.Remove(device_id);
}
var topicos_rover = Variaveis.MqttServiceLocal.Topicos.Where(x => x.Topico.Contains(device_id)).ToList();
foreach (var topico in topicos_rover)
{
await Variaveis.MqttServiceLocal.UnsubscribeAsync(topico);
Variaveis.MqttServiceLocal.Topicos.Remove(topico);
}
}
}
} }
} }

View File

@ -33,7 +33,7 @@ namespace AgroBase.Services
{ {
Task.Run(async () => Task.Run(async () =>
{ {
_mqttTopico = await Variaveis.MqttService.AdicionarNovoTopico(MqttTopico, true, 2, mqttCallback); _mqttTopico = await Variaveis.MqttServiceLocal.AdicionarNovoTopico(MqttTopico, true, 2, mqttCallback);
lock (processLock) lock (processLock)
{ {

View File

@ -955,6 +955,14 @@ namespace AgroBase.Services
LoopRTK_Ntrip = false; LoopRTK_Ntrip = false;
} }
public static void AplicarCorrecaoRTK_Mqtt(byte[] correcao, int bytesRead)
{
if (PortaGPS?.IsOpen ?? false)
{
PortaGPS.Write(correcao, 0, bytesRead);
UltimoEnvioCorrecaoRTK = DateTime.Now;
}
}
public static void AtualizarCoordenadasGPS() public static void AtualizarCoordenadasGPS()
@ -1055,8 +1063,8 @@ namespace AgroBase.Services
Task.Run(async () => Task.Run(async () =>
{ {
//Console.WriteLine(JsonConvert.SerializeObject(Coordenadas)); //Console.WriteLine(JsonConvert.SerializeObject(Coordenadas));
await Variaveis.MqttService.PublishAsync( await Variaveis.MqttServiceLocal.PublishAsync(
Variaveis.MqttService.Topicos.First(x => x.Topico == MapasVariaveisModel.TopicoCoordenadasGPS), Variaveis.MqttServiceLocal.Topicos.First(x => x.Topico == MapasVariaveisModel.TopicoCoordenadasGPS),
JsonConvert.SerializeObject(Coordenadas) JsonConvert.SerializeObject(Coordenadas)
); );
}); });
@ -1074,8 +1082,8 @@ namespace AgroBase.Services
Task.Run(async () => Task.Run(async () =>
{ {
await Variaveis.MqttService.PublishAsync( await Variaveis.MqttServiceLocal.PublishAsync(
Variaveis.MqttService.Topicos.First(x => x.Topico == MapasVariaveisModel.TopicoTrajetoriaDinamica), Variaveis.MqttServiceLocal.Topicos.First(x => x.Topico == MapasVariaveisModel.TopicoTrajetoriaDinamica),
JsonConvert.SerializeObject(Trajetoria) JsonConvert.SerializeObject(Trajetoria)
); );
}); });
@ -1086,8 +1094,8 @@ namespace AgroBase.Services
{ {
Task.Run(async () => Task.Run(async () =>
{ {
await Variaveis.MqttService.PublishAsync( await Variaveis.MqttServiceLocal.PublishAsync(
Variaveis.MqttService.Topicos.First(x => x.Topico == MapasVariaveisModel.TopicoSelecaoRuasMapa), Variaveis.MqttServiceLocal.Topicos.First(x => x.Topico == MapasVariaveisModel.TopicoSelecaoRuasMapa),
JsonConvert.SerializeObject("[" + string.Join(",", RuasSelecionadas.ToArray()) + "]"), JsonConvert.SerializeObject("[" + string.Join(",", RuasSelecionadas.ToArray()) + "]"),
true true
); );

View File

@ -13,23 +13,36 @@ public class MqttService
{ {
private IMqttClient _client; private IMqttClient _client;
private IMqttClientOptions _options; private IMqttClientOptions _options;
private string _brokerAddr;
private int _brokerPort;
private AsyncTaskTimerModel tmrCheck; private AsyncTaskTimerModel tmrCheck;
public List<MqttTopicosModel> Topicos; public List<MqttTopicosModel> Topicos;
public MqttService(string brokerAddress, int brokerPort) private void LogDebug(string msg)
{ {
Console.WriteLine($"[MQTT {_brokerAddr}:{_brokerPort}] - {msg}");
}
public MqttService(string brokerAddress, int brokerPort, string client_id, bool local)
{
_brokerAddr = brokerAddress;
_brokerPort = brokerPort;
var factory = new MqttFactory(); var factory = new MqttFactory();
_client = factory.CreateMqttClient(); _client = factory.CreateMqttClient();
string client = !local ? client_id : (client_id + "_local");
_options = new MqttClientOptionsBuilder() _options = new MqttClientOptionsBuilder()
.WithTcpServer(brokerAddress, brokerPort) .WithClientId(client)
.WithTcpServer(_brokerAddr, _brokerPort)
.WithCleanSession() .WithCleanSession()
.Build(); .Build();
_client.UseConnectedHandler(async e => _client.UseConnectedHandler(async e =>
{ {
Console.WriteLine("Connected to MQTT Broker."); LogDebug("Connected to MQTT Broker.");
if (Topicos.Any(x => x.Inscrever)) if (Topicos.Any(x => x.Inscrever))
{ {
foreach (var topic in Topicos) foreach (var topic in Topicos)
@ -37,17 +50,21 @@ public class MqttService
await SubscribeAsync(topic); await SubscribeAsync(topic);
} }
} }
}); });
_client.UseDisconnectedHandler(e => _client.UseDisconnectedHandler(e =>
{ {
Console.WriteLine("Disconnected from MQTT Broker."); LogDebug("Disconnected from MQTT Broker.");
}); });
_client.UseApplicationMessageReceivedHandler(e => _client.UseApplicationMessageReceivedHandler(e =>
{ {
string message = Encoding.UTF8.GetString((e.ApplicationMessage.Payload == null) ? new byte[] { } : e.ApplicationMessage.Payload); var payloadBytes = e.ApplicationMessage.Payload ?? Array.Empty<byte>();
var messageText = string.Empty;
// Só tenta decodificar texto se for realmente necessário
try { messageText = Encoding.UTF8.GetString(payloadBytes); } catch { /* binário puro */ }
//Console.WriteLine($"Message received on topic {e.ApplicationMessage.Topic}"); //Console.WriteLine($"Message received on topic {e.ApplicationMessage.Topic}");
// Aqui você pode adicionar o código para lidar com a mensagem recebida // Aqui você pode adicionar o código para lidar com a mensagem recebida
@ -59,7 +76,8 @@ public class MqttService
{ {
Momento = DateTime.Now, Momento = DateTime.Now,
Cliente = e.ClientId, Cliente = e.ClientId,
Mensagem = message Mensagem = messageText,
Bytes = payloadBytes
}; };
topico.Mensagens.Add(Mensagem); topico.Mensagens.Add(Mensagem);
@ -79,7 +97,7 @@ public class MqttService
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Erro no callback do tópico '{topico.Topico}': {ex}"); LogDebug($"Erro no callback do tópico '{topico.Topico}': {ex}");
} }
}); });
} }
@ -88,13 +106,7 @@ public class MqttService
Topicos = new List<MqttTopicosModel>(); Topicos = new List<MqttTopicosModel>();
Task.Run(async () => tmrCheck?.Dispose();
{
await AdicionarNovoTopico(MapasVariaveisModel.TopicoCoordenadasGPS);
await AdicionarNovoTopico(MapasVariaveisModel.TopicoSelecaoRuasMapa, true, 1, async (message) => { Variaveis.OperacaoEmAndamento.Mapa.AtualizarRuasSelecionadas(); });
await AdicionarNovoTopico(MapasVariaveisModel.TopicoTrajetoriaDinamica);
});
tmrCheck = new AsyncTaskTimerModel("tmrCheck", tmrCheck_Tick, 1000); tmrCheck = new AsyncTaskTimerModel("tmrCheck", tmrCheck_Tick, 1000);
tmrCheck.Start(); tmrCheck.Start();
} }
@ -120,7 +132,7 @@ public class MqttService
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine("Erro ao tentar se conectar ao MQTT Broker: " + ex.Message); LogDebug("Erro ao tentar se conectar ao MQTT Broker: " + ex.Message);
} }
} }
@ -150,7 +162,7 @@ public class MqttService
public async Task PublishAsync(MqttTopicosModel topic, byte[] payloadBytes, bool Forcar = false) public async Task PublishAsync(MqttTopicosModel topic, byte[] payloadBytes, bool Forcar = false)
{ {
if (topic.Inscrever && !Forcar) if (topic.Inscrever || (topic.Inscrever && !Forcar))
{ {
return; return;
} }
@ -175,11 +187,11 @@ public class MqttService
await ConnectAsync(); await ConnectAsync();
} }
await _client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic.Topico).Build()); await _client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic.Topico).Build());
Console.WriteLine("Subscribed to topic: " + topic.Topico); LogDebug($"Subscribed to topic: {topic.Topico}");
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"An error occurred while subscribing from the topic: {ex.Message}"); LogDebug($"An error occurred while subscribing from the topic: {ex.Message}");
} }
} }
@ -196,11 +208,11 @@ public class MqttService
await ConnectAsync(); await ConnectAsync();
} }
await _client.UnsubscribeAsync(new string[] { topic.Topico }); await _client.UnsubscribeAsync(new string[] { topic.Topico });
Console.WriteLine("Unsubscribed from topic: " + topic.Topico); LogDebug($"Unsubscribed from topic: {topic.Topico}");
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"An error occurred while unsubscribing from the topic: {ex.Message}"); LogDebug($"An error occurred while unsubscribing from the topic: {ex.Message}");
} }
} }
@ -247,7 +259,7 @@ public class MqttService
.Build(); .Build();
await _client.PublishAsync(mensagem); await _client.PublishAsync(mensagem);
Console.WriteLine($"Mensagem retida limpa para o tópico: {topico}"); LogDebug($"Mensagem retida limpa para o tópico: {topico}");
} }
} }
@ -265,5 +277,6 @@ public class MqttService
public DateTime Momento { get; set; } public DateTime Momento { get; set; }
public string Cliente { get; set; } public string Cliente { get; set; }
public string Mensagem { get; set; } public string Mensagem { get; set; }
public byte[] Bytes { get; set; }
} }
} }

View File

@ -1,5 +1,4 @@
using AgroBase.Forms; using AgroBase.Models;
using AgroBase.Models;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
@ -67,12 +66,7 @@ namespace AgroBase.Services
if (!string.IsNullOrEmpty(ip) && ip != Variaveis.IP_Host) if (!string.IsNullOrEmpty(ip) && ip != Variaveis.IP_Host)
{ {
bool configurado = await EthernetService.ConfigurarIP(true, false); bool configurado = await EthernetService.ConfigurarIP(true, false);
foreach (var topico in Variaveis.MqttService.Topicos.Where(x => x.Inscrever)) Variaveis.IniciarMQTT();
{
await Variaveis.MqttService.UnsubscribeAsync(topico);
}
Variaveis.MqttService.Topicos.Clear();
Variaveis.MqttService = new MqttService("localhost", 1883);
} }
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -17,6 +17,8 @@ namespace AgroMonitor
{ {
InitializeComponent(); InitializeComponent();
Variaveis.IniciarMQTT();
RedisService.Iniciar(); RedisService.Iniciar();
RedisService.LimparDadosIniciais(); RedisService.LimparDadosIniciais();
APIService.IniciarRotinas(); APIService.IniciarRotinas();
@ -58,8 +60,8 @@ namespace AgroMonitor
private async Task tmrDispositivos_Tick() private async Task tmrDispositivos_Tick()
{ {
lblMqtt.Text = "MQTT: " + (Variaveis.MqttService.StatusConexao() ? "Conectado" : "Desconectado"); lblMqtt.Text = "MQTT: " + (Variaveis.MqttServiceLocal.StatusConexao() ? "Conectado" : "Desconectado");
lblMqtt.ForeColor = Variaveis.MqttService.StatusConexao() ? Color.Green : Color.Red; lblMqtt.ForeColor = Variaveis.MqttServiceLocal.StatusConexao() ? Color.Green : Color.Red;
lblLoRa.Text = "LoRa: " + (LoRaBaseService.Iniciado ? "Conectado" : "Desconectado"); lblLoRa.Text = "LoRa: " + (LoRaBaseService.Iniciado ? "Conectado" : "Desconectado");
lblLoRa.ForeColor = LoRaBaseService.Iniciado ? Color.Green : Color.Red; lblLoRa.ForeColor = LoRaBaseService.Iniciado ? Color.Green : Color.Red;
@ -76,6 +78,8 @@ namespace AgroMonitor
{ {
tmrDispositivos.SetInterval(10000); tmrDispositivos.SetInterval(10000);
} }
VariaveisMonitoramento.AtualizarListaRoversNaRede();
} }

View File

@ -0,0 +1,47 @@
# base.py
import time, json, struct
import paho.mqtt.client as mqtt
BROKER_IP = "0.0.0.0" # se a base RODA o broker, tanto faz; para conectar, use "127.0.0.1"
RID = "rover01"
TOP_TEL = f"agrobot/{RID}/telemetry"
TOP_CMD = f"agrobot/{RID}/cmd"
last_t = None
def on_connect(c, u, f, rc):
print("Base conectada, rc=", rc)
c.subscribe(TOP_TEL, qos=0)
def on_message(c, u, msg):
global last_t
if msg.topic == TOP_TEL:
tel = json.loads(msg.payload.decode("utf-8"))
now = time.time()
if "t" in tel:
rtt_ms = (now - tel["t"]) * 1000
else:
rtt_ms = None
print(f"[TEL] vel={tel.get('vel')}, heading={tel.get('heading')}, rtt≈{rtt_ms:.1f} ms")
client = mqtt.Client(client_id="base01", clean_session=True)
client.on_connect = on_connect
client.on_message = on_message
client.connect("127.0.0.1", 1883, keepalive=60) # se a base é o broker; senão use o IP do broker
client.loop_start()
# Envia um comando binário exemplo (QoS 1)
time.sleep(1.0)
vel, ang = 0.5, 10.0
pkt = struct.pack("<ff", vel, ang)
client.publish(TOP_CMD, pkt, qos=1, retain=False)
print("[BASE] Comando enviado")
try:
while True:
time.sleep(0.5)
except KeyboardInterrupt:
pass
finally:
client.loop_stop()
client.disconnect()

View File

@ -0,0 +1,43 @@
# rover.py
import time, json, struct
import paho.mqtt.client as mqtt
BROKER_IP = "192.168.99.120" # IP da Base
RID = "rover01"
TOP_TEL = f"agrobot/{RID}/telemetry"
TOP_CMD = f"agrobot/{RID}/cmd"
TOP_HEALTH = f"agrobot/{RID}/health"
TOP_LWT = f"agrobot/{RID}/lwt"
def on_connect(c, u, f, rc):
print("Rover conectado, rc=", rc)
c.subscribe(TOP_CMD, qos=1)
# Publica estado online (retido)
c.publish(TOP_HEALTH, json.dumps({"status":"online","t":time.time()}), qos=1, retain=True)
def on_message(c, u, msg):
if msg.topic == TOP_CMD:
# Exemplo de payload binário: vel (float32), ang (float32)
vel, ang = struct.unpack("<ff", msg.payload)
print(f"[CMD] vel={vel:.2f} m/s, ang={ang:.2f}°")
client = mqtt.Client(client_id=f"{RID}", clean_session=True)
client.will_set(TOP_LWT, payload="offline", qos=1, retain=True) # LWT
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER_IP, 1883, keepalive=60)
client.loop_start()
try:
i = 0
while True:
# Telemetria json (poderia ser binário também)
tel = {"t": time.time(), "heading": 123.45+i*0.01, "vel": 1.6}
client.publish(TOP_TEL, json.dumps(tel), qos=0, retain=False)
i += 1
time.sleep(0.2)
except KeyboardInterrupt:
pass
finally:
client.loop_stop()
client.disconnect()

View File

@ -0,0 +1,13 @@
# base_tx.py
import socket, time
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ROBO_IP = "192.168.99.108"
i = 0
while True:
msg = f"PING {i}".encode()
sock.sendto(msg, (ROBO_IP, 5000))
i += 1
time.sleep(0.2)

View File

@ -0,0 +1,10 @@
# robo_rx.py
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("0.0.0.0", 5000))
print("ROBO ouvindo na porta 5000...")
while True:
data, addr = sock.recvfrom(1024)
print(f"[ROBÔ] Recebido de {addr}: {data}")