Все устройства в системе intraHouse могут существовать и без сценариев: их можно включать/выключать и смотреть за изменением их состояния. Но только сценарии сделают ваш дом по настоящему «умным». 

Концепция сценариев

Для выполнения требуемого функционала создается скрипт на языке javascript
Скрипт — это набор функций на js, которые запускаются под управлением сервера сценариев.

Скрипт может быть запущен по событиям устройств, по расписанию (времени), интерактивно.

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

Скрипты хранятся в папке проекта:
/var/lib/intrahouse-c/projects/<имя проекта>/scenes/script

Скрипты сценариев редактируется в ProjectManager разделе сценарии (но может быть отредактирован любым редактором).

Структура скрипта

Рассмотрим структуру простого скрипта на примере:

/** 
* @name Включение света при открытии двери 
* @desc Пример скрипта 
*/ 
const sensor1 = Device("SensorD","Sensor"); 
const actor1 = Device("ActorD","Включение светильника"); 

const script = {
    check() {
        return sensor1.dval == 1 || sensor1.dval == 0; 
    }, 
    start() {
        if (sensor1.dval==1)
        {this.do(actor1, "on");}
        else 
        {this.do(actor1, "off");}
    } 
}; 

Скрипт должен иметь заданную структуру, состоящую из 3 частей:

1 часть — многострочные комментарии, содержат название и описание сценария

/** 
* @name Включение света при открытии двери 
* @desc Пример скрипта
*/    

name — наименование скрипта
desc — комментарий (опционально)

2 часть — формальное определение устройств, которые будут участвовать в сценарии:

const sensor1 = Device("SensorD","Sensor"); 
const actor1 = Device("ActorD","Actor"); 

const <устройство> = Device(«<класс устройства>», «Описание устройства в рамках сценария») ,где:
<устройство> — любой допустимый идентификатор [A-Za-z0-9_]
Device — функция определения устройства
<класс устройства> — «SensorD», «SensorA», «ActorD», «ActorA»
Описание — любой комментарий, используется при создании рабочих сценариев

Например:
const sensor = Device(«SensorD», «Геркон»);
const actor = Device(«ActorD», «Светильник, который будет включаться»);

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

3 часть — объект script, который содержит функции и, возможно, переменные экземпляра рабочего сценария

const script = {
    check() {
        return sensor1.dval == 1 || sensor1.dval == 0; 
    }, 
    start() {
        if (sensor1.dval==1)
        {this.do(actor1, "on");}
        else 
        {this.do(actor1, "off");}
    } 
};

Существует два зарезервированных метода: check() и start ()
Остальные методы и переменные именуются произвольно.

Также объект скрипт получает встроенные методы для выполнения действий с устройствами, информирования, подписки на события, работы с таймерами.
Обращение к этим методам происходит через this.

Код каждой функции выполняется синхронно.
Функции скрипта не должны использовать операции ввода/вывода и таймеры (setInterval, setTimeout).
Для таймеров должны использоваться встроенные методы startTimer, stopTimer
Эти ограничения позволяют выполнять сотни сценариев в основном потоке под контролем движка сценариев.
Если необходимо, можно создать сценарий — плагин, который представляет собой полноценный модуль nodejs и будет запущен как дочерний процесс Node (fork).

Механизм обработки сценариев

При загрузке сервер сценариев создает рабочие сценарии с фактическими устройствами, но не запускает их.

Если сценарий содержит функцию check(), то автоматически выполняется подписка этого сценария на события устройств сценария, которые участвуют в условии check().

По событию любого устройства сценария запускается функция check()
Если check() возвращает true, сценарий стартует,  то есть выполняется обязательная функция start().
При запуске start() фиксируется время запуска сценария.
Функция start() может выполнить действия и завершиться.
При завершении start() фиксируется время завершения сценария.
Если же start() взводит таймеры и/или регистрирует слушателей событий, то сценарий остается запущенным (активным).

После завершения любой функции движок сценариев проверяет, есть ли у этого сценария активные таймеры или слушатели. Если нет, сценарий завершается. Но любая функция может сама вызвать this.exit() для завершения сценария. При этом активные таймеры и слушатели будут удалены. 

При любом завершении фиксируется время завершения сценария.

Переменные экземпляра сценария, объявленные в объекте script, не сбрасываются, так как сам рабочий сценарий не удаляется. Он просто переходит в неактивное состояние и будет запущен через механизм check.

Встроенные методы объекта script

do

Выполнение действия устройства: do(<устройство>, <строка-команда>)
Примеры:

Вызов метода

Действие

this.do(actor1, 'on');

включить

this.do(actor1, 'off');

выключить

this.do(actor1, 'toggle');

переключить

установить значение

log

Запись в журнал.
Примеры:

Вызов метода

В журнале будет записано

this.log(actor1.name+' вкл.');

Светильник вкл.

this.log(actor1.dn+' вкл.');

Lamp1 вкл.

this.log(actor1.name+'/'+actor1.nameOf('place')+' вкл.');

Светильник/Цоколь вкл.

this.log(actor1.name+'/'+actor1.nameOf('room')+' вкл.');

Светильник/Кухня вкл.

this.log('Температура: '+temp1.aval);

Температура: 24

Примечание:
place — уровень, room — зона
Дата и время записи в журнале подставляются автоматически.

alert

Запись в оперативный журнал.
Примеры:

Вызов метода

В журнале будет записано

this.alert(actor1.name+' вкл.');

Светильник вкл.

this.alert(actor1.dn+' вкл.');

Lamp1 вкл.

Примечание:
Другие варианты аналогично log
Дата и время записи в журнале подставляются автоматически.

addListener

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

addListener(<устройство>, <строка-имя функции>) — зарегистрировать слушателя

Пример:

start() {
	this.do(vent, 'on');
	this.addListener(temp, 'onTempChenged');
	},

onTempChenged() {
	if (temp.aval < 22)
	{
	this.do(vent, 'off');
	this.exit();
	}
    }

removeListener

removeListener (<устройство>) — удалить слушателя событий

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

Таймеры

startTimer

Запустить таймер

startTimer(<строка-имя таймера>, <число-интервал в сек>, <строка-имя функции>)

Пример:

this.startTimer('T1', 30, 'TimerDone');

Запуск таймера T1 на 30 сек. После отработки таймера вызвать функцию TimerDone()

stopTimer

Остановить запущенный таймер. Таймер переходит в состояние off.
stopTimer(<строка-имя таймера>)

Пример:

this.stopTimer('T1');

Остановить таймер T1

addTimer

Создать таймер, но пока не запускать.
addTimer(<строка-имя таймера>)

Пример:

this.addTimer('T2');

Создать таймер T2

После выполнения методов startTimer и addTimer у скрипта появляются объекты-таймеры, которые при необходимости
можно использовать в условных выражениях.

Примеры:

if (this.timer.T1 == 'off')

если таймер T1 сброшен

if (this.timer.T1 == 'on')

если таймер T1 считает

if (this.timer.T1 == 'done')

если таймер T1 счет завершил

exit

Завершить сценарий exit()

Пример:

exit();

Завершить сценарий

block

 block() — завершить сценарий и заблокировать, то есть больше не запускать.

Пример:

block();

Завершить и заблокировать сценарий

Использовать в случае выявления ошибки при выполнении скрипта.

Пример скрипта

Ниже показан пример скрипта для датчика протечки.
Если протечка длится более 5 сек, перекрывается клапан подачи воды и записывается  в журнал.
Если менее 5 сек. (датчик протечки случайно задели тряпкой) сценарий завершается без сообщений.

/**
* @name Информирование при протечке
* @desc Запись в журнал и перекрытие клапана подачи воды
*/

const leak = Device("SensorD", "Датчик протечки");
const valve = Device("ActorD", "Клапан");

const script = {
	check() {
	return leak.dval == 1;
	},

	start() {
		this.startTimer('T1', 5, 'stop'); 
		this.addListener(leak, 'leak_event');
	},

	leak_event() { 
		if (leak.dval == 0) {
			this.stopTimer('T1');		
			this.exit();
		}
	},

	stop() {
		this.do(valve, 'off');
		this.log('Протечка воды, клапан подачи воды перекрыт');
		this.exit();		
	}
};
Close Menu