суббота, 25 марта 2017 г.

ФБ "Скрипт C#" и его использование в MasterSCADA. Управление трендом – задающий график

Иногда перед разработчиками систем автоматизации встает необходимость использования задающего графика. Например – необходимо чтобы процесс шел по строго определенному графику, заданному оператору. При этом необходимо видеть оба графика – эталонный и реальный, на одном тренде. В данной статьей мы рассмотрим создание скрипта для формирования такого графика.
Задающий график создается в тренде, на продвинутом уровне при активной панели настроек. Выберем – Задание таблицей

На тренд добавится перо.

Теперь наша задача управлять данным пером – создать в нем нужные точки. Для этой цели мы будем использовать Скрипт. Для примера мы будем формировать график за сутки по 5 точками.
В дереве объектов разместим команду типа «Время» - «День», с ее помощью мы будем создавать за какой день нужно построить график. Дискретной командой «Сформировать» мы будем выполнять формирование точек пера.
Также разместим в дереве 5 одинаковых объектов – Координата 1 Координата 5. В них мы создадим команду типа Время X, и аналоговая Y. Также добавим значение Подпись – в нем мы дадим имя каждой точке («Точка 1» - «Точка 5»).

У объектов сделаем изображения объектов, в котором расположим подпись и команды X и Y. Из данных изображений скомпонуем таблицу. В итоге мнемосхема будет выглядеть примерно так.

Теперь перейдем к скрипту. Создадим у скрипта набор входов и выходов - входные сигналы даты формирования, сигнала для формирования, значения координат точек, и выходы – начало и конец для управления трендом (их мы свяжем с параметрами тренда Дата С и Дата по), и выход ошибки.

Установим связи в дереве:

И на мнемосхеме:

Теперь приступим к коду скрипта.
Формирование координат пера мы будем выполнять по сигналу на входе Применить. При этом добавим контроль что все входы имеют значения – в противном случае выдадим ошибку и выйдем из скрипта. 
   if (Применить==true && M==false) 
    { 
    if (!День.HasValue || !X1.HasValue || !X2.HasValue || !X3.HasValue || !X4.HasValue || !X5.HasValue ||
     !Y1.HasValue || !Y2.HasValue || !Y3.HasValue || !Y4.HasValue || !Y5.HasValue) 
     {
   Ошибка="Не заданы все параметры";
   return;
     }
   }
    M=Применить;  
После проверки, определить начало текущего дня, и запишем на выходы Начало и Конец.
DateTime Start=День.Value.Date;    
Начало=Start;
Конец=Start.AddDays(1);
Ранее, в одной статей, мы уже рассматривали как обратится к тренду, расположенному на мнемосхеме. 
       var проект = HostFB.TreeItemHlp.Project;        
        //получаем корневой объект
        var объект = (ITreeItemHlp)HostFB.TreeItemHlp.Parent;        
        //получаем тренд         
         RTManager.Instance.ThreadHolder.BeginInvoke(new ThreadStart(delegate
         {
            foreach (Trend trend in проект.GetService<TrendService>().Opened)
            {            
            var host = trend.Host as System.Windows.Forms.Control;            
            if (host!=null)
                {
                Object name = WinFormsControlBase.GetAmbientProperty(host, WindowlessControlBase.DISPID.DISPID_AMBIENT_NAME);
                if (name.ToString()!=ИМЯ_ТРЕНДА || trend.Attribute.TreeItem.ID!=объект.ID || trend.Attribute.DisplayName!=ИМЯ_ОКНА) continue;  
                //Теперь можно работать с трендом                

                }                
        }     
        }));   
Ранее, в одной статей, мы уже рассматривали как обратится к тренду, расположенному на мнемосхеме. 
       var проект = HostFB.TreeItemHlp.Project;        
        //получаем корневой объект
        var объект = (ITreeItemHlp)HostFB.TreeItemHlp.Parent;        
        //получаем тренд         
         RTManager.Instance.ThreadHolder.BeginInvoke(new ThreadStart(delegate
         {
            foreach (Trend trend in проект.GetService<TrendService>().Opened)
            {            
            var host = trend.Host as System.Windows.Forms.Control;            
            if (host!=null)
                {
                Object name = WinFormsControlBase.GetAmbientProperty(host, WindowlessControlBase.DISPID.DISPID_AMBIENT_NAME);
                if (name.ToString()!=ИМЯ_ТРЕНДА || trend.Attribute.TreeItem.ID!=объект.ID || trend.Attribute.DisplayName!=ИМЯ_ОКНА) continue;  
                //Теперь можно работать с трендом                

                }                
        }     
        }));   
Итак, теперь можно работать с трендом. Начнем с того, что получим перо «Задающий график». Ранее мы уже получали коллекцию перьев с помощью метода:
var list = trend.Settings.Objects.OfType<MasterSCADA.Graph.Objects.Graph2D>().ToList();
Здесь все почти тоже самое, только используется тип пера не Graph2D, а UserGraph2D.
var list = trend.Settings.Objects.OfType<MasterSCADA.Graph.Objects.UserGraph2D>().ToList();     
Продолжим – получим нулевой перо (оно у нас единственное). Затем, чтобы обратится к таблице пера (мы добавили перо с формированием по таблице) обратимся к свойству XMLTableValues. В данное свойство нужно записать коллекцию, с координатами. Каждая координата – это точка, структура Poing (описание). 
     //получаем нулевое перо
                var param=list[0];                            
                param.XMLTableValues = new GraphFigureCollection
                       {
                           new GraphFigure
                               {
                   Coords = new CoordCollection
                                        {
                                         new Coord {Logic = new Point((Start.Date+X1.Value.TimeOfDay).ToOADate(), Y1.Value)},
                                            new Coord {Logic = new Point((Start.Date+X2.Value.TimeOfDay).ToOADate(), Y2.Value)},
                                            new Coord {Logic = new Point((Start.Date+X3.Value.TimeOfDay).ToOADate(), Y3.Value)},
                                            new Coord {Logic = new Point((Start.Date+X4.Value.TimeOfDay).ToOADate(), Y4.Value)},
                                            new Coord {Logic = new Point((Start.Date+X5.Value.TimeOfDay).ToOADate(), Y5.Value)},

                                        }
                               }
                        };
В строке Start.Date+X5.Value.TimeOfDay происходит сложение даты (начала дня), и заданной пользователем координаты времени (дата отбрасывается). Затем с помощью метода ToOADate происходит преобразование формата DateTime в переменную Double, которую требует структура Point.

Наш скрипт готов. Итоговый вариант выглядит следующим образом:
public partial class ФБ : ScriptBase
{
bool? M=false;
string ИМЯ_ТРЕНДА = "Тренд";    
string ИМЯ_ОКНА = "Мнемосхема";    
    public override void Execute()
    {
    
    if (Применить==true && M==false) 
    { 
    if (!День.HasValue || !X1.HasValue || !X2.HasValue || !X3.HasValue || !X4.HasValue || !X5.HasValue ||
     !Y1.HasValue || !Y2.HasValue || !Y3.HasValue || !Y4.HasValue || !Y5.HasValue) 
     {
   Ошибка="Не заданы все параметры";
   return;
     }
    DateTime Start=День.Value.Date;    
    Начало=Start;
    Конец=Start.AddDays(1);
     //System.Diagnostics.Debug.Assert(false);
        //Ссылка на текущий проект        
        var проект = HostFB.TreeItemHlp.Project;        
        //получаем корневой объект
        var объект = (ITreeItemHlp)HostFB.TreeItemHlp.Parent;        
        //получаем тренд         
         RTManager.Instance.ThreadHolder.BeginInvoke(new ThreadStart(delegate
         {
            foreach (Trend trend in проект.GetService<TrendService>().Opened)
            {            
            var host = trend.Host as System.Windows.Forms.Control;            
            if (host!=null)
                {
                Object name = WinFormsControlBase.GetAmbientProperty(host, WindowlessControlBase.DISPID.DISPID_AMBIENT_NAME);
                if (name.ToString()!=ИМЯ_ТРЕНДА || trend.Attribute.TreeItem.ID!=объект.ID || trend.Attribute.DisplayName!=ИМЯ_ОКНА) continue;  
                //получаем коллекцию перьев                
                var list = trend.Settings.Objects.OfType<MasterSCADA.Graph.Objects.UserGraph2D>().ToList();     
                //получаем нулевое перо
                var param=list[0];                            
                param.XMLTableValues = new GraphFigureCollection
                       {
                           new GraphFigure
                               {
                   Coords = new CoordCollection
                                        {
                                         new Coord {Logic = new Point((Start.Date+X1.Value.TimeOfDay).ToOADate(), Y1.Value)},
                                            new Coord {Logic = new Point((Start.Date+X2.Value.TimeOfDay).ToOADate(), Y2.Value)},
                                            new Coord {Logic = new Point((Start.Date+X3.Value.TimeOfDay).ToOADate(), Y3.Value)},
                                            new Coord {Logic = new Point((Start.Date+X4.Value.TimeOfDay).ToOADate(), Y4.Value)},
                                            new Coord {Logic = new Point((Start.Date+X5.Value.TimeOfDay).ToOADate(), Y5.Value)},

                                        }
                               }
                        };
                }                
        }     
        }));         
    }
    M=Применить;        
    }
}
Проверим работу в режиме исполнения – выберем любую из дат, и запустим формирование координат.
Пример с готовым скриптом можно скачать по данной ссылке.

Комментариев нет:

Отправить комментарий

Поделиться