Внимание! На данный момент система поддерживает работу со скриптами только на языке JavaScript, в связи с этим для понимания этой статьи необходимо обладать базовыми навыками работы с этим языком. ====== Скрипты в DevelSCADA ====== Для расширения базового функционала среды разработки DevelSCADA, система поддерживает возможность использования скриптов. Основным языком для разработки скриптов является JavaScript. Скрипты, в свою очередь поддерживают весь функционал языка JavaScript, дополняя его функциями работы с системой DevelSCADA. Система поддерживает работу с двумя видами скриптов - **скрипты интерфейса** и **скрипты ПЛК**. Оба типа скриптов имеют идентичные интерфейсы для взаимодействия с системой, но при этом имеют разное предназначение. **Скрипты интерфейса** предназначены в первую очередь для работы с элементами пользовательского интерфейса. Они могут быть созданы как в разделе "Скрипты" дерева проектов, так и в функциях обработки событий графических элементов интерфейса. Скрипты интерфейса работают на стороне клиента в его окне интерфейса, соответственно если несколько клиентов подключены к системе одновременно, у каждого клиента будут работать собственные экземпляры скриптов. Это необходимо учитывать при необходимости синхронизации визуального представления интерфейса, если предусмотрена одновременная работа несколькими пользователями. Так же скрипты интерфейса, привязанные с событиям графических элементов экрана, работают, соответственно, только на том экране, на котором они созданы. Так же и скрипты, созданные в разделе "Скрипты", запускаются каждый раз при переходе с экрана на экран. Если проект будет запущен, но при этом к нему не будет подключено ни одного клиента, никакие скрипты интерфейса работать не будут. Если необходимо постоянная работа скриптов, вне зависимости от работы клиентов и активного экрана, для этого необходимо использовать скрипты ПЛК. **Скрипты ПЛК** запускаются сразу при старте проекта, и выполняются до тех пор, пока исполнение проекта не будет остановлено. В отличие от скриптов интерфейса, скрипты ПЛК не имеют функций прямого взаимодействия с элементами графического интерфейса, но при этом они работают постоянно, вне зависимости от того, что происходит в графическом интерфейсе. Скрипты ПЛК могут быть созданы только в разделе "Скрипты" дерева проекта. ====== Пример использования скриптов интерфейса ====== Выполнение скрипта интерфейса можно привязать к событию элемента интерфейса редактора экрана. Для примера сделаем скрипт, который будет выполняться при нажатии кнопки. Создадим в рабочей области экрана кнопку и выберем в свойствах элемента, в разделе "События", возле события "Нажатие", тип события "Скрипт". {{ ::script01.png?nolink&400 |}} После этого необходимо нажать кнопку редактирования скрипта. {{ ::script02.png?nolink&400 |}} Откроется окно текстового редактора скрипта. {{ ::script03.png?nolink&400 |}} Напишем код скрипта. async function main(val) { log('Hello world'); } Запустим проект на исполнение. При нажатии на кнопку, в системный журнал будет выводиться текст сообщения скрипта. {{ ::script04.png?nolink&400 |}} Если необходимо создать функцию, которая будет вызываться многократно из разных мест графического интерфейса, удобнее всего ее создать в разделе "Скрипты" дерева проекта. Это можно сделать правым кликом из контекстного меню, либо по кнопке "Добавить" в самом разделе. {{ ::script05.png?nolink&400 |}} В появившемся окне необходимо выбрать "Скрипт интерфейса". {{ ::script06.png?nolink&200 |}} В разделе "Скрипты" появится созданный нами скрипт, и откроется окно текстового редактора скрипта. {{ ::script07.png?nolink&600 |}} Скрипты интерфейса могут иметь функцию **init**, которая всегда вызывается при загрузке любого экрана. В ней можно выполнять какие либо подготовительные операции, необходимые для работы остального кода. Добавим в данный скрипт собственную функцию вида: export function myFunc() { log('myFunc called'); } //Внимание! Все функции, доступ к которым необходим не только из данного скрипта, обязательно должны иметь ключевое слово **export**.// В результате скрипт должен иметь следующий вид: {{ ::script08.png?nolink&400 |}} Теперь вернемся к скрипту кнопки и отредактируем его код. async function main(val) { //log('Hello world'); let mySctipt = await ds.include('script_gui0'); mySctipt.myFunc(); } Для доступа к функциям скрипта, предварительно нужно его подключить системной функцией **ds.include**, передав в качестве аргумента ей - имя скрипта. В результате в переменную **myScript** мы получим объект нашего скрипта, из которого в дальнейшем вызываем описанную в нем функцию. Теперь при нажатии на кнопку, в системный журнал будет выведено сообщение из кода функции скрипта. {{ ::script09.png?nolink&400 |}} ====== Пример использования скриптов ПЛК ====== Скрипты ПЛК создаются только в разделе "Скрипты" дерева проекта. Создается он аналогично скрипту интерфейса, с выбором соответствующего типа скрипта. {{ ::script10.png?nolink&200 |}} Для примера, создадим скрипт, который ежесекундно выводит в журнал сообщение с текущим временем. async function init() { while (true) { log('Current date:', new Date()); await ds.sleep(1000); } } Код скрипта разместим в функции **init**, которая будет вызываться при запуске проекта. После запуска проекта увидим сообщения в системном журнале, которые будут выводиться вне зависимости от того, какой экран проекта в данный момент открыт. Скрипт прекратит свое выполнение лишь после завершения выполнения проекта. {{ ::script11.png?nolink&400 |}} ====== Взаимодействие скриптов интерфейса и ПЛК ====== Скрипты интерфейса могут вызывать функции скриптов ПЛК посредством вызова функции **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; } Должен получиться проект следующего вида: {{ ::script12.png?nolink&400 |}} Далее создадим на экране две кнопки для включения и отключения статуса отображения сообщения посредством вызова функции [[ds.plccall|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**, и, соответственно, влияющая на работу таймера, выводящего сообщение. {{ ::script13.png?nolink&300 |}}