Вопрос по кодингу модуля сервера.

Стартовая страница Форумы Разработка и интеграция Вопрос по кодингу модуля сервера.

Просмотр 15 сообщений - с 1 по 15 (из 38 всего)
  • Автор
    Сообщения
  • #6907
    OldManSpb
    Участник

    Приветствую всех!
    Пытаюсь писать модуль сервера на основе ModTest. Все собирается, запускается, с этим все нормально. Мне надо обрабатывать события и отправлять каждое из них на другой сервер в своем формате. Индексов объекта, КП и др. недостаточно, необходимо получить их текстовое описание из соответствующих таблиц. Вот обработчик:

    public override void OnEventCreating(EventTableLight.Event ev)
            {
                // the method executes on event creating, event properties could be changed here
                // метод выполняется при создании события, свойства события можно изменить здесь
    
                WriteToLog("Process event creating by the module " + Name, Log.ActTypes.Action);
    
                CommSettings coms = new CommSettings();
    
                string errMsg = "Error load settings";
    
                coms.LoadFromFile(AppDirs.ConfigDir + "CommSettings.xml", out errMsg);
    
                //Так как не понимаю, в какой лог писать сделал следующее
                Log logg = new Log(Log.Formats.Simple);
                logg.FileName = "asd.log";
                logg.Capacity = 1000;
    
                ServerComm scc = new ServerComm(coms, logg);
    
                DataCache dc = new DataCache(scc, logg);
    
                DataAccess da = new DataAccess(dc, logg);
    
                //Здесь в KPNum пытаюсь получить название КП
                
                WriteToLog("Data values ===================" + "\nObjNum: " + ev.ObjNum +
                                        " |Checked: " + ev.Checked +
                                        " |CnlNum: " + ev.CnlNum +
                                        " |Data: " + ev.Data +
                                        " |DateTime: " + ev.DateTime +
                                        " |Descr: " + ev.Descr +
                                        " |KPNum: " + da.GetKPName(ev.KPNum) + //Попытка получить название КП
                                        " |NewCnlStat: " + ev.NewCnlStat +
                                        " |NewCnlVal: " + ev.NewCnlVal +
                                        " |Number: " + ev.Number + //Почему-то всегда возвращает ноль
                                        " |ObjNum: " + ev.ObjNum +
                                        " |OldCnlStat: " + ev.OldCnlStat +
                                        " |OldCnlVal: " + ev.OldCnlVal +
                                        " |ParamID: " + ev.ParamID +
                                        " |UserID: " + ev.UserID, Log.ActTypes.Action);

    Вот вывод лога:

    2017-08-04 11:39:05 <GM><система><ACT> Data values ===================
    ObjNum: 2 |Checked: False |CnlNum: 1702 |Data:  |DateTime: 04.08.2017 11:38:59 |Descr:  |KPNum:  |NewCnlStat: 13 |NewCnlVal: 65,1126556396484 |Number: 0 |ObjNum: 2 |OldCnlStat: 15 |OldCnlVal: 65,838134765625 |ParamID: 23 |UserID: 0

    Что не так:
    Во-первых, ID события всегда выдает 0.
    Во-вторых не получается получить текстовые описания из таблиц.
    Тыкните меня пожалуйста носом, что я делаю неправильно?

    #6910
    OldManSpb
    Участник

    Номер события из обработчика EventCreating дает 0 и из EventCreated тоже 0.

    #6914
    Mikhail
    Модератор

    Номер события из обработчика EventCreating дает 0 и из EventCreated тоже 0.

    Это исправлено в ветке develop и при следующем релизе войдёт в master.

    Текст события генерируется довольно хитро. Опять же в ветке develop есть подвижки по этому вопросу. См. здесь.

    Вам надо загрузить базу конфигурации из файлов dat, чтобы получить наименования объектов, КП и т.д. Актуальный путь к базе Вы можете найти в переменных, доступных в модуле.

    #6915
    Mikhail
    Модератор

    В новом Модуле автоуправления недавно решались похожие задачи.

    #6919
    OldManSpb
    Участник

    Михаил, спасибо за ответ.

    #6924
    OldManSpb
    Участник

    Насчет модуля автоуправления. Я бы добавил туда ПИ регулятор. И тогда можно было бы им делать вообще все что угодно. Извиняюсь за оффтоп.

    #6936
    Mikhail
    Модератор

    Думаю, что ПИД-регулятор лучше сделать отдельным модулем, т.к. он специфичен. И ещё отличается тем, что регулятор подаёт команды постоянно, а модуль автоуправления всё-таки относительно редко — разный подход.

    Но пока с коммерческой точки зрения модуль регулятора не очень востребован, может быть кто-то сделает и выложит или, наоборот, закажет и оплатит разработку.

    #6944
    manjey73
    Участник

    Регулятор можно сделать формулой в канале, а когда в Модуле появится возможность посылать данные по изменению то и проблема снимется.

    #6950
    OldManSpb
    Участник

    P — регулятор, да, можно формулой, или я не прав и можно и интегральный регулятор сделать формулой? Мне возможно понадобится в будущем, когда понадобится буду разбираться.

    #6955
    manjey73
    Участник

    Да по идее все можно написать формулами. Если выход у регулятора один, то будет формула вида PID(Val(1), Val(2), Val(3)) — где Val(x) номера каналов отвечающие за настройки PID, интегральная составляющая, дифференциальная и так далее, все что необходимо для расчета.
    Если выходов 2 и более, тогда придется разбивать на несколько частей формулу.

    Надо посмотреть код регуляторов на C для ПК или Ардуино, или например на ST для ПЛК ну и сделать ее на C# для использования в RapidScada.

    Если найдете на языке LD для ПЛК то можно и так сделать, но много каналов может потребоваться для реализации.

    #6957
    OldManSpb
    Участник

    Хорошо, а ограничение выходного значения можно сделать? Или ограничение диапазона интегрирования в I компоненте?

    #6958
    manjey73
    Участник

    Так все зависит от кода, если нужно ограничение по выходу, можно использовать код ScaleR на выходе или в самом коде PID.
    Формула — это по сути обычный программный код функции, как напишите, так и будет работать.

    #6969
    OldManSpb
    Участник

    =Выкладываю класс для модуля сервера, который позволяет получать названия большинства полей события, а также получать номер события, который в текущей версии не передается в обработчики.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Scada.Data.Models;
    using Scada.Data.Tables;
    using Scada.Server.Modules;
    using Scada.Client;
    using System.Data;
    
    namespace Scada.Server.Modules
    {
        class DataTablesAccess
        {
    
            public DataTablesAccess(string PathToConfig)
            {
                string pathToconfig = PathToConfig;// "C:\\SCADA\\BaseDAT\\";
    
              
    
                baseTables = new BaseTables();
    
                baseAdapter = new BaseAdapter();
    
                baseAdapter.FileName = pathToconfig + BaseTables.GetFileName(baseTables.KPTable);
    
                baseAdapter.Fill(baseTables.KPTable,true);
    
                baseAdapter.FileName = pathToconfig + BaseTables.GetFileName(baseTables.ObjTable);
    
                baseAdapter.Fill(baseTables.ObjTable, true);
    
                baseAdapter.FileName = pathToconfig + BaseTables.GetFileName(baseTables.InCnlTable);
    
                baseAdapter.Fill(baseTables.InCnlTable, true);
    
                baseAdapter.FileName = pathToconfig + BaseTables.GetFileName(baseTables.ParamTable);
    
                baseAdapter.Fill(baseTables.ParamTable, true);
    
                baseAdapter.FileName = pathToconfig + BaseTables.GetFileName(baseTables.EvTypeTable);
    
                baseAdapter.Fill(baseTables.EvTypeTable, true);
    
                baseAdapter.FileName = pathToconfig + BaseTables.GetFileName(baseTables.UserTable);
    
                baseAdapter.Fill(baseTables.UserTable, true);
    
               
    
                
            }
            
            public string GetKPNameByNubber (int KPNum)
            {
              DataRow[] dataRow;  
    
              dataRow = baseTables.KPTable.Select("KPNum = " + KPNum);
    
                if (dataRow.Length > 0)
                    return dataRow[0][1].ToString();
                else
                    return "No such KP";
               
            }
            public string GetObjectNameByNumber(int ObjNum)
            {
                DataRow[] dataRow;
    
                dataRow = baseTables.ObjTable.Select("ObjNum = " + ObjNum);
                if (dataRow.Length > 0)
                    return dataRow[0][1].ToString();
                else
                    return "No Such Object";
            }
    
            public string GetChannelNameByNumber(int ChNum)
            {
                DataRow[] dataRow;
    
                dataRow = baseTables.InCnlTable.Select("CnlNum = " + ChNum);
                if (dataRow.Length > 0)
                    return dataRow[0][2].ToString();
                else
                    return "No Such Channel";
            }
            public string GetParametrName(int ParamNo)
            {
                DataRow[] dataRow;
    
                dataRow = baseTables.ParamTable.Select("ParamID = " + ParamNo);
                if (dataRow.Length > 0)
                    return dataRow[0][1].ToString();
                else
                    return "No Such Param";
            }
            
            public string GetEventTypeText(int ChStat)
            {
    
                DataRow[] dataRow;
    
                dataRow = baseTables.EvTypeTable.Select("CnlStatus = " + ChStat);
                if (dataRow.Length > 0)
                    return dataRow[0][1].ToString();
                else
                    return "No Such Status";
                  
            }
    
            public string GetUserName(int userNo)
            {
                DataRow[] dataRow;
    
                dataRow = baseTables.UserTable.Select("UserID = " + userNo);
                if (dataRow.Length > 0)
                    return dataRow[0][1].ToString();
                else
                    return "No Such User";
    
            }
    
            public int GetLastEventNo()
            {
                string tableName = "C:\\SCADA\\ArchiveDAT\\Events\\" + "e" + DateTime.Now.ToString("yyMMdd") + ".dat";
    
                EventTableLight eventTable = new EventTableLight();
    
                EventAdapter eventAdapter = new EventAdapter();
    
                eventAdapter.FileName = tableName;
    
                eventAdapter.Fill(eventTable);
    
                List<EventTableLight.Event> temp = new List<EventTableLight.Event>();
    
                temp = eventTable.GetLastEvents(1);
    
                if (temp.Count > 0)
                    return temp[0].Number;
                else
                    return 0;
            }
            private BaseTables baseTables;
    
            private BaseAdapter baseAdapter;
    
         
    
        }
    }
    
    #6974
    Mikhail
    Модератор

    Спасибо за код. Однако рекомендую выкладывать исходники на GitHub, а в форуме оставлять ссылку на код. Так будет проще найти этот код в будущем.

    #6984
    OldManSpb
    Участник

    Мой модуль иногда подглючивает после перезапуска сервера, всвязи с этим вопрос: При перезапуске сервера каждый раз вызывается конструктор модуля, либо только дергаются методы OnServerStart и OnServerStop?

Просмотр 15 сообщений - с 1 по 15 (из 38 всего)
  • Вы должны авторизироваться для ответа в этой теме.