javascript

Скрипты в DevelSCADA

  • четверг, 9 октября 2025 г. в 00:00:02
https://habr.com/ru/articles/954694/

Для расширения базового функционала среды разработки DevelSCADA, система поддерживает возможность использования скриптов. Основным языком для разработки скриптов является JavaScript. Скрипты, в свою очередь поддерживают весь функционал языка JavaScript, дополняя его функциями работы с системой DevelSCADA.

Система поддерживает работу с двумя видами скриптов - скрипты интерфейса и скрипты ПЛК. Оба типа скриптов имеют идентичные интерфейсы для взаимодействия с системой, но при этом имеют разное предназначение.

Скрипты интерфейса предназначены в первую очередь для работы с элементами пользовательского интерфейса. Они могут быть созданы как в разделе «Скрипты» дерева проектов, так и в функциях обработки событий графических элементов интерфейса. Скрипты интерфейса работают на стороне клиента в его окне интерфейса, соответственно если несколько клиентов подключены к системе одновременно, у каждого клиента будут работать собственные экземпляры скриптов. Это необходимо учитывать при необходимости синхронизации визуального представления интерфейса, если предусмотрена одновременная работа несколькими пользователями. Так же скрипты интерфейса, привязанные с событиям графических элементов экрана, работают, соответственно, только на том экране, на котором они созданы. Так же и скрипты, созданные в разделе «Скрипты», запускаются каждый раз при переходе с экрана на экран. Если проект будет запущен, но при этом к нему не будет подключено ни одного клиента, никакие скрипты интерфейса работать не будут. Если необходимо постоянная работа скриптов, вне зависимости от работы клиентов и активного экрана, для этого необходимо использовать скрипты ПЛК.

Скрипты ПЛК запускаются сразу при старте проекта, и выполняются до тех пор, пока исполнение проекта не будет остановлено. В отличие от скриптов интерфейса, скрипты ПЛК не имеют функций прямого взаимодействия с элементами графического интерфейса, но при этом они работают постоянно, вне зависимости от того, что происходит в графическом интерфейсе. Скрипты ПЛК могут быть созданы только в разделе «Скрипты» дерева проекта.

Пример использования скриптов интерфейса

Выполнение скрипта интерфейса можно привязать к событию элемента интерфейса редактора экрана. Для примера сделаем скрипт, который будет выполняться при нажатии кнопки. Создадим в рабочей области экрана кнопку и выберем в свойствах элемента, в разделе «События», возле события «Нажатие», тип события «Скрипт».

После этого необходимо нажать кнопку редактирования скрипта.

Откроется окно текстового редактора скрипта.

Напишем код скрипта.

async function main(val) {
    log('Hello world');
}

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

Если необходимо создать функцию, которая будет вызываться многократно из разных мест графического интерфейса, удобнее всего ее создать в разделе «Скрипты» дерева проекта. Это можно сделать правым кликом из контекстного меню, либо по кнопке «Добавить» в самом разделе.

В появившемся окне необходимо выбрать «Скрипт интерфейса».

В разделе «Скрипты» появится созданный нами скрипт, и откроется окно текстового редактора скрипта.

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

export function myFunc() {
    log('myFunc called');
}

Внимание! Все функции, доступ к которым необходим не только из данного скрипта, обязательно должны иметь ключевое слово export.

В результате скрипт должен иметь следующий вид:

Теперь вернемся к скрипту кнопки и отредактируем его код.

async function main(val) {
    //log('Hello world');
    let mySctipt = await ds.include('script_gui0');
    mySctipt.myFunc();
}

Для доступа к функциям скрипта, предварительно нужно его подключить системной функцией ds.include, передав в качестве аргумента ей - имя скрипта. В результате в переменную myScript мы получим объект нашего скрипта, из которого в дальнейшем вызываем описанную в нем функцию.

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

Пример использования скриптов ПЛК

Скрипты ПЛК создаются только в разделе «Скрипты» дерева проекта. Создается он аналогично скрипту интерфейса, с выбором соответствующего типа скрипта.

Для примера, создадим скрипт, который ежесекундно выводит в журнал сообщение с текущим временем.

async function init() {
    while (true) {
        log('Current date:', new Date());
        await ds.sleep(1000);
    }
}

Код скрипта разместим в функции init, которая будет вызываться при запуске проекта. После запуска проекта увидим сообщения в системном журнале, которые будут выводиться вне зависимости от того, какой экран проекта в данный момент открыт. Скрипт прекратит свое выполнение лишь после завершения выполнения проекта.

Взаимодействие скриптов интерфейса и ПЛК

Скрипты интерфейса могут вызывать функции скриптов ПЛК посредством вызова функции callPlc. При этом скрипты ПЛК не могут напрямую обращаться к функциям скриптов интерфейса. Это связано с тем, что контекстов исполнения скриптов интерфейса может быть несколько, или не быть ни одного, а контекст выполнения скриптов ПЛК всегда существует, и он всегда один. В связи с этим реализация доступа из скриптов ПЛК к функциям скриптов интерфейса не была реализована, чтобы не усложнять работу системы дополнительными проверками их доступности и синхронизацией. Если же необходимо из скриптов ПЛК влиять на работу скриптов интерфейса, то это можно легко реализовать, используя общие переменные устройства «Память».

Пример вызова функции скрипта ПЛК из скрипта интерфейса

Создадим в скаде код логики работы некоего устройства. К примеру сделаем таймер на 3 секунды, который будет выводить сообщение в журнал. Так же создадим функцию, которая будет управлять состоянием видимости сообщения. Так как этот код должен работать постоянно при работе проекта, его необходимо создать в скрипте ПЛК. Для этого создадим скрипт следующего вида:

let isActive = true;
 
async function init() {
    while (true) {
        if (isActive) log('hi');
        await ds.sleep(3000);
    }
}
 
function setActive(state) {
    log('Set state:', state);
    isActive = state;
}

Должен получиться проект следующего вида:

Далее создадим на экране две кнопки для включения и отключения статуса отображения сообщения посредством вызова функции ds.plcCall, которая вызывает функцию из скрипта ПЛК. Создадим в кнопках скрипты следующего содержания:

async function main(val) {
    await ds.plcCall('script_plc0.setActive', [ true ]);
}

и

async function main(val) {
    await ds.plcCall('script_plc0.setActive', [ false ]);
}

Запустим проект и понажимаем кнопки, в журнале будет видно как вызывается функция ПЛК setActive, изменяющая содержимое переменной isActive, и, соответственно, влияющая на работу таймера, выводящего сообщение.