Функции (формулы) для Rapid SCADA

Стартовая страница Форумы Понять, как работает ПО Формулы Функции (формулы) для Rapid SCADA

Просмотр 15 сообщений - с 76 по 90 (из 150 всего)
  • Автор
    Записи
  • #31119
    manjey73
    Участник

    Что-то я не уверен, что можно скриптом со связью на мнемосхемах на данном моменте.
    Мнемосхемы еще от 5-й версии, каких-то нововведений вроде не было.

    #31120
    Michael
    Участник

    Что-то я не уверен, что можно скриптом со связью на мнемосхемах на данном моменте.

    Тут вопрос больше, как в скрипте использовать возможности c# по открытию ссылки в дефолтном браузере, код типа

    ProcessStartInfo sInfo = new ProcessStartInfo("http://example.com/");
    Process.Start(sInfo);
    #31121
    a80808
    Участник

    Из скриптов мне процесс запустить не удавалось…

    #31122
    manjey73
    Участник

    Скрипты работают от системного пользователя, там кажется с этим связаны проблемы запуска сторонних приложений.

    Может быть есть обходные пути через bat файлы, но опять же не уверен.

    Вообще было бы полезным что-то запускать. Может Михаил подскажет как это обойти.

    Например точно можно создать файл из скрипта, например это будет bat файл.
    А уже средствами системы как-то его запустить ????
    Например в Linux через crontab точно можно сварганить подобное легко.

    Scada создает любой файл с текстом банально true — false а сриптом через crontab проверять и что-то запускать.
    В Windows хз, не страдал, но думаю через планировщик и свой bat тоже можно сделать.

    • Ответ изменён 2 года, 6 месяцев назад пользователем manjey73.
    • Ответ изменён 2 года, 6 месяцев назад пользователем manjey73.
    • Ответ изменён 2 года, 6 месяцев назад пользователем manjey73.
    #31126
    a80808
    Участник

    Пробовал через bat — не получается. Там похоже нет возможности новый процесс запустить…

    #31127
    a80808
    Участник

    Планировщик в Виндах тоже есть. Не пробовал. Не успел…
    Подвисал программный шлюз, я хотел анализировать метку времени. Если не меняется — перезагрузка.

    #31128
    a80808
    Участник

    А собственно ссылку открыть через «Пустой документ» или в Дэшбордах можно..
    Вот только как там разные ссылки открывать?

    #31129
    Michael
    Участник

    Например точно можно создать файл из скрипта, например это будет bat файл.

    Код поскажете на будущее? Вдруг пригодится (но мы все равно будем ждать Михаила )))

    #31130
    manjey73
    Участник

    @Michael делал для передачи каналов по SNMP — смотрите запись в файл здесь.
    Это для Linux, для Windows другой путь надо указывать в строке path…

    // Список каналов создается формулой SnmpData(Cnl) для входных каналов
    //
    string pathSnmp = @"/var/log/scada/ScadaServer/Log/snmpdata.txt";
    protected Dictionary<int, double> snmpData = new Dictionary<int, double>();
    
    public double SnmpData (double res)
    {
    if (!snmpData.ContainsKey(CnlNum))
    {
    snmpData.Add(CnlNum, res);
    }
    else
    {
    snmpData[CnlNum] = res;
    }
    return res;
    }
    
    public double SnmpRead(int cnlNum)
    {
    return snmpData[cnlNum];
    }
    
    // Сохранить данные выбранных каналов в файл данных SNMP
    public double SaveSnmpData()
    {
    File.WriteAllLines(pathSnmp, snmpData
      .Select(pair => String.Join(" ", pair.Key, pair.Value.ToString().Replace(",","."))));
    return snmpData.Count;
    }
    
    #31131
    manjey73
    Участник

    Смысл в том, что записать файл из формул можно, как на Linux так и на Windows.
    Что в этот файл писать уже дело десятое.

    А вот свой скрипт в планировщике уже ваять так как вам надо с проверкой файла, который вам будет писать Scada.

    Еще поищите скрипты retain, я выкладывал ранее, там тоже запись и чтение файла было.

    • Ответ изменён 2 года, 6 месяцев назад пользователем manjey73.
    #31133
    manjey73
    Участник
    // Чтение датчиков Dallas ds18b20 из файла, созданного скриптом в crontab
    string pathLog = @"/var/log/scada/ScadaComm/Log/";
    
    public double ds18b20(string dsID)
    {
    double res = Double.NaN;
    
    string filePath = Path.Combine(pathLog, dsID);
    
    if (File.Exists(filePath))
    {
    string[] DataDs = File.ReadAllLines(filePath, Encoding.UTF8);
    
    int iOfChar = DataDs[1].IndexOf("t=");
    
    int temp =  int.Parse(DataDs[1].Substring(iOfChar+2));
    
    res = Convert.ToDouble(temp)/1000;
    }
    
    if (res == Double.NaN) SetStat(CnlNum, 0);
    return res;
    }
    

    Вот пример чтения файла и запись данных в каналы из формул Scada. Я так датчики температуры читаю. Скрипт в crontab файл с данными записывает, а scada читает.

    #31134
    manjey73
    Участник
    #!/bin/bash
    pathfile="/opt/scada/ScadaComm/Config/ds1820.txt"
    dssave="/var/log/scada/ScadaComm/Log/"
    
    declare -a dsname
    unset dsname
    
    readarray -t dsname < $pathfile
    
    #let i=0
    #while IFS=$'\n' read -r line_data; do
    #    dsname[i]="${line_data}"
    #    ((++i))
    #done < $pathfile
    
    for ((i=0;  i <  ${#dsname[*]}; i++ )); do
        cat /sys/bus/w1/devices/${dsname[i]}/w1_slave > $dssave${dsname[i]}
    done
    
    exit 0
    

    Собственно скрипт для чтения датчиков на моей OrangePi+ 2E
    Правда его надо положить в какое-то место, чтобы scada его не затирала и назначить права на исполнение.

    И входная формула в канале датчика ds18b20("28-031683f5c0ff") — пример. файл создается с именем = серийнику датчика.

    • Ответ изменён 2 года, 6 месяцев назад пользователем manjey73.
    #31136
    Algomus
    Участник

    Генераратор импульсов длительностью 1 цикл программы DelGen.
    Может быть полезен для периодического опроса.
    Циклограмма:
    __—————-_____ Вх
    _____-___-___-______ Вых

    int[] DelGenNum = new int[1];
    long[] DelGenST = new long[1];
    bool[] DelGenFlag = new bool[1];
    public bool DelGen(double DelGenIn, long DelGenPT)
    {
    long ET = 0L;
    bool q = Val(CnlNum) > 0;
    bool delgen_in = DelGenIn > 0;

    int res = Array.IndexOf(DelGenNum, CnlNum);
    if (res == -1)
    {
    res = DelGenNum.Length;
    Array.Resize(ref DelGenNum, res+1);
    Array.Resize(ref DelGenST, res+1);
    Array.Resize(ref DelGenFlag, res+1);
    DelGenNum[res] = CnlNum;
    }

    if (!delgen_in || q)
    {
    q = false;
    DelGenFlag[res] = false;
    DelGenST[res] = 0L;
    }
    else
    {
    if (!DelGenFlag[res])
    {
    DelGenFlag[res] = true;
    DelGenST[res] = Ticks();
    }
    else
    {
    if (!q) ET = Ticks() — DelGenST[res];
    }

    if (ET >= DelGenPT) q = true;

    }
    return q;
    }

    DelGen(значение канала в double, время в миллисекундах)
    Пример: в канале 152 используем формулу DelGen(Val(150), 5000) — при появлении 1 на входном канале 150 на канале 152 через 5000 мсек будут появляться импульсы длительностью 1 цикл программы.

    • Ответ изменён 2 года, 6 месяцев назад пользователем Algomus.
    #31138
    manjey73
    Участник

    Сейчас пробую сделать тот же Ton используя не массивы а словари.
    По количеству строк может и не меньше сильно, но как-то красивее что ли 🙂

    Как проверю, выложу.

    #31139
    manjey73
    Участник

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

    // Таймеры МЭК и другие
    public static long Ticks()
    {
    DateTime now = DateTime.Now;
    long time = now.Ticks/10000;
    return time;
    }
    
    protected class UtilTimer
    {
    public long et;
    public bool flag;
    }
    
    protected Dictionary<int, UtilTimer> CDSTimer = new Dictionary<int, UtilTimer>();
    
    // Таймер с задержкой включения TON
    public double TON(double IN, double PT)
    {
    var ut = new UtilTimer() {et = 0L, flag = false};
    
    long ET = 0L;
    long _pt = Convert.ToInt64(PT);
    bool q = Val(CnlNum) > 0;
    bool _in = IN > 0;
    
    if (!CDSTimer.ContainsKey(CnlNum))
    {
    CDSTimer.Add(CnlNum, ut);
    }
    
    if (!_in)
    {
    q = false;
    CDSTimer[CnlNum].flag = false;
    CDSTimer[CnlNum].et = 0L;
    }
    else
    {
    if (!CDSTimer[CnlNum].flag)
    {
    CDSTimer[CnlNum].flag = true;
    CDSTimer[CnlNum].et = Ticks();
    }
     else
     {
       if (!q) ET = Ticks() - CDSTimer[CnlNum].et;
     }
     if (ET >= _pt) q = true;
    }
    return Convert.ToDouble(q);
    }

    Пока только TON — сделал заглавными буквами, если оставить один Ticks то не должен конфликтовать с Ton
    Так же класс UtilTimer и словарь CDSTimer будет использоваться для остальных таймеров.

Просмотр 15 сообщений - с 76 по 90 (из 150 всего)
  • Для ответа в этой теме необходимо авторизоваться.