Создайте службу для извлечения данных из ПЛК с помощью библиотеки EasyModbusTCP.

Для начала: я не программист и начал изучать это всего несколько месяцев назад.

Я создал программу WPF, используя библиотеку EasyModbusTCP, которая работает! и даже удалось прочитать Modbus асинхронно, чтобы он не зависал.

Теперь есть необходимость расширить эту программу, чтобы вытащить из Modbus более 600 катушек и регистров. Попутно перехожу на паттерн MVVM с помощью CommunityToolkit.

Я не знаю и, честно говоря, озадачен тем, как создать сервис внутри ViewModel.

Приложение теперь слишком сложное, чтобы отображать полный код, поэтому я упрощу его, насколько это возможно. Мое представление — это UserControl, у которого есть ItemsControl с коллекцией другого UserControl в качестве ItemsSource.

XAML-просмотр проводимости:

      <ItemsControl Grid.Row="2" ItemsSource="{Binding ConductivityTanks}">
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="{x:Type vm:ConductivityGridElementViewModel}">
                <controls:ConductivityGridElement DataContext="{Binding}"></controls:ConductivityGridElement>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

Код позади:

      public partial class BConductivityView : UserControl
{
    ConductivityViewModel conductivityViewModel;
    public BConductivityView()
    {
        InitializeComponent();
        conductivityViewModel = new ConductivityViewModel();
        this.DataContext = conductivityViewModel;
    }
}

В моей модели ConductivityViewModel мне нужно вставить будущую службу извлечения Modbus и сделать ее асинхронной.

      public partial class ConductivityViewModel : ObservableObject
{ 
    [ObservableProperty]
    private ObservableCollection<ConductivityGridElementViewModel> _conductivityTanks;

    public ConductivityViewModel()
    {
        _conductivityTanks = new ObservableCollection<ConductivityGridElementViewModel>();

        ConductivityTanks.Clear();
        //Add some initial dummy data to display
        for (int i = 0; i <= 32; i++)
        {
            ConductivityTanks.Add(new ConductivityGridElementViewModel
            {
                Id = i.ToString(),
                Use = true,
                TankNo = i.ToString(),
                Sp = (1000 + i).ToString(),
                Pv = (1500 + i).ToString(),
                Valve = false,
                TimeLeft = (4 + i).ToString(),
                Timer = (5).ToString(),
                SensorMinimum = "0",
                SensorMaximum = "10000",
                Raw = "1670"
            });
        }

        public void ModbusReadAsync()
        {
             // Make async call to start modbus pull and update all ConductivityGridElement in ConductivityTanks
        }
    }
}

Мой класс обслуживания Modbus читает ПЛК и назначает статические поля в статических классах, все это выглядит следующим образом:

      public static class ModbusService
{
    public static CancellationTokenSource cts = new CancellationTokenSource();
    public static ModbusClient MB = new ModbusClient();
    private static bool[] coils1 = new bool[120];
    private static bool[] coils2 = new bool[40];
    private static int[] registers1 = new int[121];
    private static int[] registers2 = new int[121];
    private static int[] registers3 = new int[121];

    public static void ConnectToPLC(string IP, int Port, bool ReConnect)
    {
        cts.Cancel();
        ConnectionExist = false;
        MB.Disconnect();
        MB = new ModbusClient(IP, Port);
        try
        {
            MB.Connect();
            ConnectionExist = true;
            ReadPLCAsync();
        }
        catch (Exception)
        {
            MessageBox.Show("Connection error.\r\nStart without reading PLC.");
        }
    }

    public static async void ReadPLCAsync()
    {
        await Task.Run(async () =>
        {
            await Read(cts.Token);
        });
    }


    private static async Task<bool> Read(CancellationToken cancellationToken)
    {
        while (ConnectionExist)
        {
            try
            {
                coils1 = MB.ReadCoils(0, 120);
                coils2 = MB.ReadCoils(121, 40);

                registers1 = MB.ReadHoldingRegisters(0, 122);
                registers2 = MB.ReadHoldingRegisters(122, 122);
                registers3 = MB.ReadHoldingRegisters(244, 122);

                General.CPUinRUN = coils1[0];
                General.ValveON = coils1[1];
                General.SDCardEject = coils1[2];
                General.SDCardEject = coils1[3];
                Conductivity.MasterON = coils1[4];
                Fresh.MasterON = coils1[5];
                Level.MasterON = coils1[6];
                General.SendEmail = coils1[7];

                Array.Copy(coils1, 8, Conductivity.Valve, 0, 32);
                Array.Copy(coils1, 40, Conductivity.CValveMan, 0, 32);

                Array.Copy(coils1, 72, Fresh.FValve, 0, 32);
                Fresh.RunOnSaturday = coils1[104];
                Fresh.RunOnSunday = coils1[105];
                Fresh.RunOnWeekend = coils1[106];

                Array.Copy(coils1, 107, Level.L_Alarm, 0, 10);
                Array.Copy(coils1, 117, Level.L_AlarmOFF, 0, 5);
                Array.Copy(coils2, 0, Level.L_AlarmOFF, 5, 5);
                Array.Copy(coils2, 5, Level.L_Filling, 0, 10);
                Array.Copy(coils2, 15, Level.L_InRange, 0, 10);
                Array.Copy(coils2, 25, Level.L_Valve, 0, 10);

                Conductivity.ON = coils2[35];
                Fresh.ON = coils2[36];
                Level.ON = coils2[37];
            }
            catch (ConnectionException)
            {
                ConnectionExist = false;
                MBC.MB.Disconnect();
                MessageBox.Show("Problem reading PLC from MBC class.");

            }
            await Task.Delay(1000);
        }
        return true;

    }

}

В целом приложение выглядит так

0 ответов

Другие вопросы по тегам