bico pode ser ligado e desligado com o tempo parametrizado

This commit is contained in:
Diego Freitas 2026-08-13 21:11:55 -03:00
parent b72d0c4666
commit fce03f5044
2 changed files with 210 additions and 13 deletions

View File

@ -5,9 +5,11 @@ using AgroBase.Models.Operadores;
using AgroBase.Services; using AgroBase.Services;
using AgroBase.Services.Operadores; using AgroBase.Services.Operadores;
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using static AgroBase.Models.Enums; using static AgroBase.Models.Enums;
@ -388,7 +390,9 @@ namespace AgroBase.Forms.IHM.Operacao
if (!(op?.Parametros?.Controle?.ControleManualAcionado ?? false)) if (!(op?.Parametros?.Controle?.ControleManualAcionado ?? false))
return; return;
var bico = op?.DispAtu?.Dados?.BicosPulverizadores?.FirstOrDefault(x => x.ID == card.Codigo); string bicoId = card.Codigo;
var bico = op?.DispAtu?.Dados?.BicosPulverizadores?.FirstOrDefault(x => x.ID == bicoId);
if (bico == null) if (bico == null)
return; return;
@ -400,7 +404,107 @@ namespace AgroBase.Forms.IHM.Operacao
setarControle: true, setarControle: true,
status: card.CommandOn status: card.CommandOn
); );
bool ligar = !card.CommandOn;
int tempoAtuacaoMs = Math.Max(0, op?.Parametros?.Controle?.AtuDuracaoAtuacao ?? 0);
// Qualquer comando novo invalida o timer anterior deste bico.
CancelarTemporizadorBico(bicoId);
op?.DispAtu?.Dados?.EnviarComandoFisicoBico(
bico,
CanMessagePosicaoDados.Command1,
setarControle: true,
status: ligar
);
if (ligar && tempoAtuacaoMs > 0)
{
_ = ProgramarDesligamentoBicoAsync(
bicoId,
tempoAtuacaoMs,
() =>
{
op?.DispAtu?.Dados?.EnviarComandoFisicoBico(
bico,
CanMessagePosicaoDados.Command1,
setarControle: true,
status: false
);
} }
);
}
}
private readonly ConcurrentDictionary<string, CancellationTokenSource> _temporizadoresBicos = new ConcurrentDictionary<string, CancellationTokenSource>(StringComparer.OrdinalIgnoreCase);
private void CancelarTemporizadorBico(string bicoId)
{
if (_temporizadoresBicos.TryRemove(bicoId, out var temporizador))
{
try
{
temporizador.Cancel();
}
finally
{
temporizador.Dispose();
}
}
}
private async Task ProgramarDesligamentoBicoAsync(string bicoId, int tempoAtuacaoMs, Action desligar)
{
CancelarTemporizadorBico(bicoId);
var cts = new CancellationTokenSource();
if (!_temporizadoresBicos.TryAdd(bicoId, cts))
{
cts.Dispose();
return;
}
try
{
await Task.Delay(
TimeSpan.FromMilliseconds(tempoAtuacaoMs),
cts.Token
);
// Garante que este ainda é o temporizador mais recente do bico.
if (_temporizadoresBicos.TryGetValue(
bicoId,
out var atual) &&
ReferenceEquals(atual, cts))
{
desligar();
}
}
catch (OperationCanceledException)
{
// Outro comando substituiu ou cancelou esta atuação.
}
catch (Exception ex)
{
Models.Variaveis.MostrarLog(
$"Erro no desligamento temporizado do bico {bicoId}: {ex.Message}"
);
}
finally
{
if (_temporizadoresBicos.TryGetValue(
bicoId,
out var atual) &&
ReferenceEquals(atual, cts))
{
_temporizadoresBicos.TryRemove(bicoId, out _);
}
cts.Dispose();
}
}

View File

@ -10,6 +10,7 @@ using AgroMonitor;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Globalization; using System.Globalization;
@ -554,7 +555,7 @@ namespace AgroBase.Models
DistanciaManobra = 3.0, DistanciaManobra = 3.0,
AtuAlturaAreaPulverizacao = 10, AtuAlturaAreaPulverizacao = 10,
AtuDuracaoAtuacao = 200, AtuDuracaoAtuacao = 2000,
AtuPercentualErvasBicoOff = 2, AtuPercentualErvasBicoOff = 2,
AtuPercentualErvasBicoOn = 1, AtuPercentualErvasBicoOn = 1,
AtuPercentualInicioPulverizacao = 85, AtuPercentualInicioPulverizacao = 85,
@ -668,7 +669,7 @@ namespace AgroBase.Models
DistanciaManobra = 3.0, DistanciaManobra = 3.0,
AtuAlturaAreaPulverizacao = 10, AtuAlturaAreaPulverizacao = 10,
AtuDuracaoAtuacao = 200, AtuDuracaoAtuacao = 0,
AtuPercentualErvasBicoOff = 2, AtuPercentualErvasBicoOff = 2,
AtuPercentualErvasBicoOn = 1, AtuPercentualErvasBicoOn = 1,
AtuPercentualInicioPulverizacao = 85, AtuPercentualInicioPulverizacao = 85,
@ -812,7 +813,7 @@ namespace AgroBase.Models
DistanciaManobra = 3.0, DistanciaManobra = 3.0,
AtuAlturaAreaPulverizacao = 10, AtuAlturaAreaPulverizacao = 10,
AtuDuracaoAtuacao = 200, AtuDuracaoAtuacao = 0,
AtuPercentualErvasBicoOff = 2, AtuPercentualErvasBicoOff = 2,
AtuPercentualErvasBicoOn = 1, AtuPercentualErvasBicoOn = 1,
AtuPercentualInicioPulverizacao = 85, AtuPercentualInicioPulverizacao = 85,
@ -954,7 +955,7 @@ namespace AgroBase.Models
DistanciaManobra = 3.0, DistanciaManobra = 3.0,
AtuAlturaAreaPulverizacao = 10, AtuAlturaAreaPulverizacao = 10,
AtuDuracaoAtuacao = 200, AtuDuracaoAtuacao = 0,
AtuPercentualErvasBicoOff = 2, AtuPercentualErvasBicoOff = 2,
AtuPercentualErvasBicoOn = 1, AtuPercentualErvasBicoOn = 1,
AtuPercentualInicioPulverizacao = 85, AtuPercentualInicioPulverizacao = 85,
@ -1056,7 +1057,7 @@ namespace AgroBase.Models
DistanciaManobra = 3.0, DistanciaManobra = 3.0,
AtuAlturaAreaPulverizacao = 10, AtuAlturaAreaPulverizacao = 10,
AtuDuracaoAtuacao = 200, AtuDuracaoAtuacao = 0,
AtuPercentualErvasBicoOff = 2, AtuPercentualErvasBicoOff = 2,
AtuPercentualErvasBicoOn = 1, AtuPercentualErvasBicoOn = 1,
AtuPercentualInicioPulverizacao = 85, AtuPercentualInicioPulverizacao = 85,
@ -2671,6 +2672,72 @@ namespace AgroBase.Models
); );
} }
private readonly ConcurrentDictionary<string, CancellationTokenSource> _temporizadoresBicos = new ConcurrentDictionary<string, CancellationTokenSource>(StringComparer.OrdinalIgnoreCase);
private void CancelarTemporizadorBico(string bicoId)
{
if (_temporizadoresBicos.TryRemove(bicoId, out var temporizador))
{
try
{
temporizador.Cancel();
}
finally
{
temporizador.Dispose();
}
}
}
private async Task ProgramarDesligamentoBicoAsync(string bicoId, int tempoAtuacaoMs, Action desligar)
{
CancelarTemporizadorBico(bicoId);
var cts = new CancellationTokenSource();
if (!_temporizadoresBicos.TryAdd(bicoId, cts))
{
cts.Dispose();
return;
}
try
{
await Task.Delay(
TimeSpan.FromMilliseconds(tempoAtuacaoMs),
cts.Token
);
// Garante que este ainda é o temporizador mais recente do bico.
if (_temporizadoresBicos.TryGetValue(
bicoId,
out var atual) &&
ReferenceEquals(atual, cts))
{
desligar();
}
}
catch (OperationCanceledException)
{
// Outro comando substituiu ou cancelou esta atuação.
}
catch (Exception ex)
{
Models.Variaveis.MostrarLog(
$"Erro no desligamento temporizado do bico {bicoId}: {ex.Message}"
);
}
finally
{
if (_temporizadoresBicos.TryGetValue(
bicoId,
out var atual) &&
ReferenceEquals(atual, cts))
{
_temporizadoresBicos.TryRemove(bicoId, out _);
}
cts.Dispose();
}
}
private void ExecutarComandoAtuador(OperacaoComandoBaseModel controleBase, OperacaoModel op) private void ExecutarComandoAtuador(OperacaoComandoBaseModel controleBase, OperacaoModel op)
{ {
if (controleBase.Controle == null) if (controleBase.Controle == null)
@ -2701,7 +2768,8 @@ namespace AgroBase.Models
return; return;
case S_Code.sBIC: case S_Code.sBIC:
var bico = dadosAtu.BicosPulverizadores?.FirstOrDefault(x => x.ID == controleBase._comp_id); var bicoId = controleBase._comp_id;
var bico = dadosAtu.BicosPulverizadores?.FirstOrDefault(x => x.ID == bicoId);
if (controleBase._comp_value != null) if (controleBase._comp_value != null)
{ {
@ -2714,13 +2782,38 @@ namespace AgroBase.Models
} }
} }
dadosAtu?.EnviarComandoFisicoBico( bool ligar = controleBase.Controle.Estado == true;
int tempoAtuacaoMs = Math.Max(0, op?.Parametros?.Controle?.AtuDuracaoAtuacao ?? 0);
double anguloComando = controleBase?.Controle?.AnguloSP ?? 0;
// Qualquer comando novo invalida o timer anterior deste bico.
CancelarTemporizadorBico(bicoId);
dadosAtu.EnviarComandoFisicoBico(
bico, bico,
CanMessagePosicaoDados.Command1, CanMessagePosicaoDados.Command1,
setarControle: true, setarControle: true,
status: controleBase.Controle.Estado == true, status: ligar,
angulo: controleBase.Controle.AnguloSP angulo: anguloComando
); );
if (ligar && tempoAtuacaoMs > 0)
{
_ = ProgramarDesligamentoBicoAsync(
bicoId,
tempoAtuacaoMs,
() =>
{
dadosAtu.EnviarComandoFisicoBico(
bico,
CanMessagePosicaoDados.Command1,
setarControle: true,
status: false,
angulo: anguloComando
);
}
);
}
return; return;
case S_Code.sBMB: case S_Code.sBMB: