12 063
правки
(Подготовка страницы к переводу) |
(Отметить эту версию для перевода) |
||
Строка 1: | Строка 1: | ||
<languages/> | <languages/> | ||
<translate> | <translate> | ||
<!--T:1--> | |||
[[File:Wb rules demo.png|400px|thumb|right|Редактирование правил в веб-интерфейсе]] | [[File:Wb rules demo.png|400px|thumb|right|Редактирование правил в веб-интерфейсе]] | ||
Для контроллера можно писать правила, например: "Если температура датчика меньше 18°С, включи нагреватель". Правила создаются через [[Special:MyLanguage/Веб-интерфейс Wiren Board|веб-интерфейс]] и пишутся на простом языке, похожем на Javascript. | Для контроллера можно писать правила, например: "Если температура датчика меньше 18°С, включи нагреватель". Правила создаются через [[Special:MyLanguage/Веб-интерфейс Wiren Board|веб-интерфейс]] и пишутся на простом языке, похожем на Javascript. | ||
<!--T:2--> | |||
Самое полное описание движка правил: https://github.com/contactless/wb-rules | Самое полное описание движка правил: https://github.com/contactless/wb-rules | ||
== Как создавать и редактировать правила == | == Как создавать и редактировать правила == <!--T:3--> | ||
<!--T:4--> | |||
*Список файлов с правилами находится на странице ''Scripts'' веб-интерфейса. | *Список файлов с правилами находится на странице ''Scripts'' веб-интерфейса. | ||
*Нажмите на название файла, чтобы открыть его для редактирования. | *Нажмите на название файла, чтобы открыть его для редактирования. | ||
Строка 20: | Строка 23: | ||
== Пишем первое правило == | == Пишем первое правило == <!--T:5--> | ||
<!--T:6--> | |||
[[File:Web-scripts-rule1.png|400px|thumb|Правило для управления обогревателем, записанное через веб-интерфейс]] | [[File:Web-scripts-rule1.png|400px|thumb|Правило для управления обогревателем, записанное через веб-интерфейс]] | ||
<!--T:7--> | |||
Правила бывают двух типов - непосредственно правила (начинаются со слов ''defineRule'') и виртуальные устройства (начинаются со слов ''defineVirtualDevice''). Виртуальные устройства - это появляющиеся в веб-интерфейсе новые элементы управления - например, кнопка-выключатель, которая на самом деле выключает два устройства одновременно. Она не привязана напрямую ни к какому физическому устройству, а действия при её нажатии определяются написанным вами скриптом. | Правила бывают двух типов - непосредственно правила (начинаются со слов ''defineRule'') и виртуальные устройства (начинаются со слов ''defineVirtualDevice''). Виртуальные устройства - это появляющиеся в веб-интерфейсе новые элементы управления - например, кнопка-выключатель, которая на самом деле выключает два устройства одновременно. Она не привязана напрямую ни к какому физическому устройству, а действия при её нажатии определяются написанным вами скриптом. | ||
<!--T:8--> | |||
Любое количество разных правил можно хранить в одном файле. Обычно в одном файле хранятся правила, отвечающие за близкие функции. | Любое количество разных правил можно хранить в одном файле. Обычно в одном файле хранятся правила, отвечающие за близкие функции. | ||
=== Первое правило === | === Первое правило === <!--T:9--> | ||
<!--T:10--> | |||
Для начала разберём простое правило - при превышении температуры выключи обогреватель. Температуру получаем с датчика [[Special:MyLanguage/1-Wire|1-Wire]], обогреватель подключён к Реле 1 внешнего релейного модуля [[Special:MyLanguage/WB-MRM2|WB-MRM2]]. | Для начала разберём простое правило - при превышении температуры выключи обогреватель. Температуру получаем с датчика [[Special:MyLanguage/1-Wire|1-Wire]], обогреватель подключён к Реле 1 внешнего релейного модуля [[Special:MyLanguage/WB-MRM2|WB-MRM2]]. | ||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
<!--T:11--> | |||
defineRule("heater_control", { //название правила - "контроль обогревателя", может быть произвольным | defineRule("heater_control", { //название правила - "контроль обогревателя", может быть произвольным | ||
whenChanged: "wb-w1/28-0115a48fcfff", //при изменении состояния датчика 1-Wire с идентификатором 28-0115a48fcfff | whenChanged: "wb-w1/28-0115a48fcfff", //при изменении состояния датчика 1-Wire с идентификатором 28-0115a48fcfff | ||
Строка 46: | Строка 54: | ||
}); | }); | ||
<!--T:12--> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
*Первая строка - кодовое слово ''defineRule'' и название правила | *Первая строка - кодовое слово ''defineRule'' и название правила | ||
Строка 55: | Строка 64: | ||
=== Первое правило с виртуальным устройством === | === Первое правило с виртуальным устройством === <!--T:13--> | ||
<!--T:14--> | |||
Создаём виртуальный переключатель, при нажатии на который переключаются сразу два реле. | Создаём виртуальный переключатель, при нажатии на который переключаются сразу два реле. | ||
<!--T:15--> | |||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
defineVirtualDevice("switch_both", { | defineVirtualDevice("switch_both", { | ||
Строка 70: | Строка 81: | ||
}); | }); | ||
<!--T:16--> | |||
defineRule("control_both", { | defineRule("control_both", { | ||
whenChanged: "switch_both/enabled", | whenChanged: "switch_both/enabled", | ||
Строка 81: | Строка 93: | ||
=== Пишем сложные правила === | === Пишем сложные правила === <!--T:17--> | ||
<!--T:18--> | |||
Чтобы начать писать сложные правила, нужно посмотреть примеры правил и полную документацию по движку правил: | Чтобы начать писать сложные правила, нужно посмотреть примеры правил и полную документацию по движку правил: | ||
#Примеры правил: | #Примеры правил: | ||
Строка 91: | Строка 104: | ||
== Примеры правил == | == Примеры правил == <!--T:19--> | ||
=== Слежение за контролом === | === Слежение за контролом === <!--T:20--> | ||
<!--T:21--> | |||
Это простейшее правило следит за контролом и устанавливает другой контрол в такое же состояние. | Это простейшее правило следит за контролом и устанавливает другой контрол в такое же состояние. | ||
<!--T:22--> | |||
Например правило может включать сирену и лампу, если датчик движения заметил движение. | Например правило может включать сирену и лампу, если датчик движения заметил движение. | ||
<!--T:23--> | |||
В примере датчик движения подключен к входу "сухой контакт", контрол типа "switch". Сирена подключена к встроеному реле Wiren Board, а лампа - через релейный блок по Modbus. Когда вход типа "сухой контакт" (выход датчика движения) замкнут, то на лампу и реле подаётся "1", когда выключен - "0". | В примере датчик движения подключен к входу "сухой контакт", контрол типа "switch". Сирена подключена к встроеному реле Wiren Board, а лампа - через релейный блок по Modbus. Когда вход типа "сухой контакт" (выход датчика движения) замкнут, то на лампу и реле подаётся "1", когда выключен - "0". | ||
<!--T:24--> | |||
Правило срабатывает каждый раз при изменении значения контрола "D1_IN" у устройства "wb-gpio". В код правила передаётся новое значение этого контрола в виде переменной newValue. | Правило срабатывает каждый раз при изменении значения контрола "D1_IN" у устройства "wb-gpio". В код правила передаётся новое значение этого контрола в виде переменной newValue. | ||
<!--T:25--> | |||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
<!--T:26--> | |||
defineRule("motion_detector", { | defineRule("motion_detector", { | ||
whenChanged: "wb-gpio/D1_IN", | whenChanged: "wb-gpio/D1_IN", | ||
Строка 113: | Строка 132: | ||
dev["wb-mrm2_6"]["Relay 1"] = newValue; | dev["wb-mrm2_6"]["Relay 1"] = newValue; | ||
} | <!--T:27--> | ||
} | |||
}); | }); | ||
<!--T:28--> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
<!--T:29--> | |||
То же самое, но с виртуальным девайсом в качестве источника событий. Пример использования: сценарная кнопка, которая включает/выключает сирену и лампочку. | То же самое, но с виртуальным девайсом в качестве источника событий. Пример использования: сценарная кнопка, которая включает/выключает сирену и лампочку. | ||
<!--T:30--> | |||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
defineVirtualDevice("simple_test", { | defineVirtualDevice("simple_test", { | ||
Строка 133: | Строка 156: | ||
<!--T:31--> | |||
defineRule("simple_switch", { | defineRule("simple_switch", { | ||
whenChanged: "simple_test/enabled", | whenChanged: "simple_test/enabled", | ||
Строка 139: | Строка 163: | ||
dev["wb-mrm2_6"]["Relay 1"] = newValue; | dev["wb-mrm2_6"]["Relay 1"] = newValue; | ||
} | <!--T:32--> | ||
} | |||
}); | }); | ||
<!--T:33--> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Детектор движения c таймаутом === | === Детектор движения c таймаутом === <!--T:34--> | ||
<!--T:35--> | |||
На вход D2 подключен детектор движения с выходом типа "сухой контакт", который замыкает D2 и GND при обнаружении движения. | На вход D2 подключен детектор движения с выходом типа "сухой контакт", который замыкает D2 и GND при обнаружении движения. | ||
При этом, на канале "wb-gpio/D2_IN" появляется статус "1". | При этом, на канале "wb-gpio/D2_IN" появляется статус "1". | ||
<!--T:36--> | |||
Правило включает свет при обнаружении движения и выключает свет, спустя 30 секунд после пропадания сигнала с датчика движения. | Правило включает свет при обнаружении движения и выключает свет, спустя 30 секунд после пропадания сигнала с датчика движения. | ||
<!--T:37--> | |||
Освещение подключено через встроенное реле, канал wb-gpio/Relay_1. | Освещение подключено через встроенное реле, канал wb-gpio/Relay_1. | ||
<!--T:38--> | |||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
<!--T:39--> | |||
var motion_timer_1_timeout_ms = 30 * 1000; | var motion_timer_1_timeout_ms = 30 * 1000; | ||
var motion_timer_1_id = null; | var motion_timer_1_id = null; | ||
<!--T:40--> | |||
defineRule("motion_detector_1", { | defineRule("motion_detector_1", { | ||
whenChanged: "wb-gpio/D2_IN", | whenChanged: "wb-gpio/D2_IN", | ||
Строка 166: | Строка 198: | ||
dev["wb-gpio"]["Relay_1"] = 1; | dev["wb-gpio"]["Relay_1"] = 1; | ||
if (motion_timer_1_id) { | <!--T:41--> | ||
if (motion_timer_1_id) { | |||
clearTimeout(motion_timer_1_id); | clearTimeout(motion_timer_1_id); | ||
} | } | ||
Строка 178: | Строка 211: | ||
}); | }); | ||
<!--T:42--> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Создание однотипных правил === | === Создание однотипных правил === <!--T:43--> | ||
<!--T:44--> | |||
Если таких детекторов движения нужно несколько, то, чтобы не копировать код, можно обернуть создание правила и переменных в функцию: | Если таких детекторов движения нужно несколько, то, чтобы не копировать код, можно обернуть создание правила и переменных в функцию: | ||
<!--T:45--> | |||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
function makeMotionDetector(name, timeout_ms, detector_control, relay_control) { | function makeMotionDetector(name, timeout_ms, detector_control, relay_control) { | ||
Строка 198: | Строка 234: | ||
} | } | ||
motion_timer_id = setTimeout(function() { | <!--T:46--> | ||
motion_timer_id = setTimeout(function() { | |||
dev["wb-gpio"][relay_control] = 0; | dev["wb-gpio"][relay_control] = 0; | ||
motion_timer_id = null; | motion_timer_id = null; | ||
Строка 207: | Строка 244: | ||
} | } | ||
<!--T:47--> | |||
makeMotionDetector("motion_detector_1", 20000, "EXT1_DR1", "EXT2_R3A1"); | makeMotionDetector("motion_detector_1", 20000, "EXT1_DR1", "EXT2_R3A1"); | ||
makeMotionDetector("motion_detector_2", 10000, "EXT1_DR2", "EXT2_R3A2"); | makeMotionDetector("motion_detector_2", 10000, "EXT1_DR2", "EXT2_R3A2"); | ||
Строка 214: | Строка 252: | ||
=== Активация правила только в определённое время === | === Активация правила только в определённое время === <!--T:48--> | ||
<!--T:49--> | |||
Правило как в предыдущем разделе, но выполняется только с 9:30 до 17:10 по UTC. | Правило как в предыдущем разделе, но выполняется только с 9:30 до 17:10 по UTC. | ||
<!--T:50--> | |||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
var motion_timer_1_timeout_ms = 5 * 1000; | var motion_timer_1_timeout_ms = 5 * 1000; | ||
Строка 227: | Строка 267: | ||
var date = new Date(); | var date = new Date(); | ||
// time point marking the beginning of the interval | <!--T:51--> | ||
// time point marking the beginning of the interval | |||
// i.e. "today, at HH:MM". All dates are in UTC! | // i.e. "today, at HH:MM". All dates are in UTC! | ||
var date_start = new Date(date); | var date_start = new Date(date); | ||
Строка 233: | Строка 274: | ||
date_start.setMinutes(30); | date_start.setMinutes(30); | ||
// time point marking the end of the interval | <!--T:52--> | ||
// time point marking the end of the interval | |||
var date_end = new Date(date); | var date_end = new Date(date); | ||
date_end.setHours(17); | date_end.setHours(17); | ||
Строка 259: | Строка 301: | ||
=== Роллеты === | === Роллеты === <!--T:53--> | ||
<!--T:54--> | |||
Одно реле включает двигатель, поднимающий шторы, второе реле - включает двигатель, опускающий шторы. | Одно реле включает двигатель, поднимающий шторы, второе реле - включает двигатель, опускающий шторы. | ||
Правило следит за тем, чтобы оба реле не были включены одновременно. | Правило следит за тем, чтобы оба реле не были включены одновременно. | ||
<!--T:55--> | |||
Кроме этого, правило отключает двигатели спустя заданное время после включения. | Кроме этого, правило отключает двигатели спустя заданное время после включения. | ||
<!--T:56--> | |||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
(function() { //don't touch this line | (function() { //don't touch this line | ||
Строка 274: | Строка 319: | ||
var relay_up_control = "Relay 1"; | var relay_up_control = "Relay 1"; | ||
var relay_down_device = "lc103_4"; | <!--T:57--> | ||
var relay_down_device = "lc103_4"; | |||
var relay_down_control = "Relay 2"; | var relay_down_control = "Relay 2"; | ||
var timeout_s = 15; | <!--T:58--> | ||
var timeout_s = 15; | |||
// End of settings | // End of settings | ||
Строка 294: | Строка 341: | ||
}; | }; | ||
relay_up_timer_id = setTimeout(function() { | <!--T:59--> | ||
relay_up_timer_id = setTimeout(function() { | |||
return dev[relay_up_device][relay_up_control] = 0; | return dev[relay_up_device][relay_up_control] = 0; | ||
}, timeout_s * 1000); | }, timeout_s * 1000); | ||
Строка 300: | Строка 348: | ||
}); | }); | ||
defineRule("roller_shutter_down_on" + suffix, { | <!--T:60--> | ||
defineRule("roller_shutter_down_on" + suffix, { | |||
asSoonAs: function() { | asSoonAs: function() { | ||
return dev[relay_down_device][relay_down_control]; | return dev[relay_down_device][relay_down_control]; | ||
Строка 315: | Строка 364: | ||
}); | }); | ||
defineRule("roller_shutter_both_on" + suffix, { | <!--T:61--> | ||
defineRule("roller_shutter_both_on" + suffix, { | |||
asSoonAs: function() { | asSoonAs: function() { | ||
return dev[relay_up_device][relay_up_control] && dev[relay_down_device][relay_down_control]; | return dev[relay_up_device][relay_up_control] && dev[relay_down_device][relay_down_control]; | ||
Строка 324: | Строка 374: | ||
}; | }; | ||
if (relay_down_timer_id) { | <!--T:62--> | ||
if (relay_down_timer_id) { | |||
relay_down_timer_id = clearTimeout(relay_down_timer_id); | relay_down_timer_id = clearTimeout(relay_down_timer_id); | ||
}; | }; | ||
dev[relay_up_device][relay_up_control] = 0; | <!--T:63--> | ||
dev[relay_up_device][relay_up_control] = 0; | |||
dev[relay_down_device][relay_down_control] = 0; | dev[relay_down_device][relay_down_control] = 0; | ||
log("Both roller shutter relays on, switching them off"); | log("Both roller shutter relays on, switching them off"); | ||
Строка 339: | Строка 391: | ||
<!--T:64--> | |||
Более старая версия того же сценария демонстрирует использование alias-ов: | Более старая версия того же сценария демонстрирует использование alias-ов: | ||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
<!--T:65--> | |||
(function() { | (function() { | ||
defineAlias("relay_up_1", "lc103_4/Relay 1"); | defineAlias("relay_up_1", "lc103_4/Relay 1"); | ||
Строка 347: | Строка 401: | ||
var timeout_s = 15; | var timeout_s = 15; | ||
defineRule("roller_shutter_1_up_on", { | <!--T:66--> | ||
defineRule("roller_shutter_1_up_on", { | |||
asSoonAs: function() { | asSoonAs: function() { | ||
return relay_up_1; | return relay_up_1; | ||
Строка 358: | Строка 413: | ||
}); | }); | ||
defineRule("roller_shutter_1_down_on", { | <!--T:67--> | ||
defineRule("roller_shutter_1_down_on", { | |||
asSoonAs: function() { | asSoonAs: function() { | ||
return relay_down_1; | return relay_down_1; | ||
Строка 369: | Строка 425: | ||
}); | }); | ||
defineRule("roller_shutter_1_both_on", { | <!--T:68--> | ||
defineRule("roller_shutter_1_both_on", { | |||
asSoonAs: function() { | asSoonAs: function() { | ||
return relay_up_1 && relay_down_1; | return relay_up_1 && relay_down_1; | ||
Строка 381: | Строка 438: | ||
})(); | })(); | ||
<!--T:69--> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Системные правила === | === Системные правила === <!--T:70--> | ||
<!--T:71--> | |||
Некоторые правила поставляются с системой правил по умолчанию в пакете wb-rules-system. | Некоторые правила поставляются с системой правил по умолчанию в пакете wb-rules-system. | ||
<!--T:72--> | |||
Полный список правил [https://github.com/contactless/wb-rules-system/tree/master/rules в репозитории]. | Полный список правил [https://github.com/contactless/wb-rules-system/tree/master/rules в репозитории]. | ||
<!--T:73--> | |||
Некоторые примеры: | Некоторые примеры: | ||
==== Правило для пищалки ==== | ==== Правило для пищалки ==== <!--T:74--> | ||
<!--T:75--> | |||
[https://github.com/contactless/wb-rules-system/blob/master/rules/buzzer.js Правило] создаёт виртуальное устройство buzzer с ползунками для регулировки громкости и частоты, а также кнопкой включения звука. | [https://github.com/contactless/wb-rules-system/blob/master/rules/buzzer.js Правило] создаёт виртуальное устройство buzzer с ползунками для регулировки громкости и частоты, а также кнопкой включения звука. | ||
<!--T:76--> | |||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
defineVirtualDevice("buzzer", { | defineVirtualDevice("buzzer", { | ||
title: "Buzzer", // | title: "Buzzer", // | ||
cells: { | <!--T:77--> | ||
cells: { | |||
frequency : { | frequency : { | ||
type : "range", | type : "range", | ||
Строка 423: | Строка 487: | ||
<!--T:78--> | |||
// setup pwm2 | // setup pwm2 | ||
runShellCommand("echo 2 > /sys/class/pwm/pwmchip0/export"); | runShellCommand("echo 2 > /sys/class/pwm/pwmchip0/export"); | ||
Строка 428: | Строка 493: | ||
<!--T:79--> | |||
function _buzzer_set_params() { | function _buzzer_set_params() { | ||
var period = parseInt(1.0 / dev.buzzer.frequency * 1E9); | var period = parseInt(1.0 / dev.buzzer.frequency * 1E9); | ||
Строка 433: | Строка 499: | ||
runShellCommand("echo " + period + " > /sys/class/pwm/pwmchip0/pwm2/period"); | <!--T:80--> | ||
runShellCommand("echo " + period + " > /sys/class/pwm/pwmchip0/pwm2/period"); | |||
runShellCommand("echo " + duty_cycle + " > /sys/class/pwm/pwmchip0/pwm2/duty_cycle"); | runShellCommand("echo " + duty_cycle + " > /sys/class/pwm/pwmchip0/pwm2/duty_cycle"); | ||
}; | }; | ||
<!--T:81--> | |||
defineRule("_system_buzzer_params", { | defineRule("_system_buzzer_params", { | ||
whenChanged: [ | whenChanged: [ | ||
Строка 444: | Строка 512: | ||
], | ], | ||
then: function (newValue, devName, cellName) { | <!--T:82--> | ||
then: function (newValue, devName, cellName) { | |||
if ( dev.buzzer.enabled) { | if ( dev.buzzer.enabled) { | ||
_buzzer_set_params(); | _buzzer_set_params(); | ||
Строка 452: | Строка 521: | ||
<!--T:83--> | |||
defineRule("_system_buzzer_onof", { | defineRule("_system_buzzer_onof", { | ||
whenChanged: "buzzer/enabled", | whenChanged: "buzzer/enabled", | ||
Строка 466: | Строка 536: | ||
<!--T:84--> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
==== Правило для статуса питания ==== | ==== Правило для статуса питания ==== <!--T:85--> | ||
<!--T:86--> | |||
[https://github.com/contactless/wb-rules-system/blob/master/rules/power_status.js Правило] создаёт виртуальное устройство, которое сообщает текущий статус питания. В качестве входных данных используется два канала АЦП: измерение напряжения на аккумуляторе и измерение входного напряжения. | [https://github.com/contactless/wb-rules-system/blob/master/rules/power_status.js Правило] создаёт виртуальное устройство, которое сообщает текущий статус питания. В качестве входных данных используется два канала АЦП: измерение напряжения на аккумуляторе и измерение входного напряжения. | ||
<!--T:87--> | |||
Реализована следующая логика: | Реализована следующая логика: | ||
<!--T:88--> | |||
1. Если входное напряжение меньше напряжение на аккумуляторе, то значит плата питается от аккумулятора. В этом случае, также отображается 0V в качестве входного напряжения. | 1. Если входное напряжение меньше напряжение на аккумуляторе, то значит плата питается от аккумулятора. В этом случае, также отображается 0V в качестве входного напряжения. | ||
<!--T:89--> | |||
2. Если входное напряжение больше напряжения на аккумуляторе, то плата работает от внешнего источника питания. В качестве входонго напряжения отображается измерение с канала Vin. | 2. Если входное напряжение больше напряжения на аккумуляторе, то плата работает от внешнего источника питания. В качестве входонго напряжения отображается измерение с канала Vin. | ||
<!--T:90--> | |||
Для иллюстрации правила используют два разных способа срабатывания: по изменению значения контрола (правило _system_track_vin) и по изменению значения выражения (два других). | Для иллюстрации правила используют два разных способа срабатывания: по изменению значения контрола (правило _system_track_vin) и по изменению значения выражения (два других). | ||
<!--T:91--> | |||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
<!--T:92--> | |||
defineVirtualDevice("power_status", { | defineVirtualDevice("power_status", { | ||
title: "Power status", // | title: "Power status", // | ||
cells: { | <!--T:93--> | ||
cells: { | |||
'working on battery' : { | 'working on battery' : { | ||
type : "switch", | type : "switch", | ||
Строка 500: | Строка 579: | ||
} | <!--T:94--> | ||
} | |||
}); | }); | ||
<!--T:95--> | |||
defineRule("_system_track_vin", { | defineRule("_system_track_vin", { | ||
whenChanged: "wb-adc/Vin", | whenChanged: "wb-adc/Vin", | ||
Строка 518: | Строка 599: | ||
<!--T:96--> | |||
defineRule("_system_dc_on", { | defineRule("_system_dc_on", { | ||
asSoonAs: function () { | asSoonAs: function () { | ||
Строка 527: | Строка 609: | ||
}); | }); | ||
<!--T:97--> | |||
defineRule("_system_dc_off", { | defineRule("_system_dc_off", { | ||
asSoonAs: function () { | asSoonAs: function () { | ||
Строка 536: | Строка 619: | ||
}); | }); | ||
<!--T:98--> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Отправка команд по RS-485 === | === Отправка команд по RS-485 === <!--T:99--> | ||
<!--T:100--> | |||
Для примера отправим команду устройству на порт ''/dev/ttyNSC0'' (соответствует аппаратному порту RS-485-ISO на [[Special:MyLanguage/Wiren Board 4|Wiren Board 4]]). | Для примера отправим команду устройству на порт ''/dev/ttyNSC0'' (соответствует аппаратному порту RS-485-ISO на [[Special:MyLanguage/Wiren Board 4|Wiren Board 4]]). | ||
Для этого будем использовать движок правил и возможность выполнения произвольных shell-команд. Подробнее см. [https://github.com/contactless/wb-rules#%D0%94%D1%80%D1%83%D0%B3%D0%B8%D0%B5-%D0%BF%D1%80%D0%B5%D0%B4%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D1%91%D0%BD%D0%BD%D1%8B%D0%B5-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8-%D0%B8-%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5 в документации]. | Для этого будем использовать движок правил и возможность выполнения произвольных shell-команд. Подробнее см. [https://github.com/contactless/wb-rules#%D0%94%D1%80%D1%83%D0%B3%D0%B8%D0%B5-%D0%BF%D1%80%D0%B5%D0%B4%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D1%91%D0%BD%D0%BD%D1%8B%D0%B5-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8-%D0%B8-%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5 в документации]. | ||
<!--T:101--> | |||
С помощью движка правил создадим виртуальное устройство с контролом типа switch (переключатель). | С помощью движка правил создадим виртуальное устройство с контролом типа switch (переключатель). | ||
<!--T:102--> | |||
При включении переключателя будем отправлять команду (уст. Яркость кан. 00=0xff) для Uniel UCH-M141: | При включении переключателя будем отправлять команду (уст. Яркость кан. 00=0xff) для Uniel UCH-M141: | ||
<pre> | <pre> | ||
Строка 553: | Строка 640: | ||
<!--T:103--> | |||
При выключении переключателя будем отправлять команду (уст. Яркость кан. 00=0x00) для Uniel UCH-M141: | При выключении переключателя будем отправлять команду (уст. Яркость кан. 00=0x00) для Uniel UCH-M141: | ||
<pre> | <pre> | ||
Строка 562: | Строка 650: | ||
<!--T:104--> | |||
1. Настройка порта | 1. Настройка порта | ||
<!--T:105--> | |||
Для настройки порта /dev/ttyNSC0 на скорость 9600 надо выполнить следующую команду | Для настройки порта /dev/ttyNSC0 на скорость 9600 надо выполнить следующую команду | ||
<!--T:106--> | |||
<pre> | <pre> | ||
stty -F /dev/ttyNSC0 ospeed 9600 ispeed 9600 raw clocal -crtscts -parenb -echo cs8 | stty -F /dev/ttyNSC0 ospeed 9600 ispeed 9600 raw clocal -crtscts -parenb -echo cs8 | ||
</pre> | </pre> | ||
<!--T:107--> | |||
2. Отправка команды | 2. Отправка команды | ||
<!--T:108--> | |||
Отправка данных делается следующей шелл-командой: | Отправка данных делается следующей шелл-командой: | ||
<!--T:109--> | |||
<pre> | <pre> | ||
/usr/bin/printf '\xFF\xFF\x0A\x01\xD1\x06\x00\xE2' >/dev/ttyNSC0 | /usr/bin/printf '\xFF\xFF\x0A\x01\xD1\x06\x00\xE2' >/dev/ttyNSC0 | ||
Строка 580: | Строка 674: | ||
<!--T:110--> | |||
3. Создадим в движке правил новый файл с правилами <code>/etc/wb-rules/rs485_cmd.js</code> | 3. Создадим в движке правил новый файл с правилами <code>/etc/wb-rules/rs485_cmd.js</code> | ||
<!--T:111--> | |||
Файл можно редактировать с помощью vim, nano или mcedit в сеансе ssh на устройстве, либо залить его с помощью SCP. | Файл можно редактировать с помощью vim, nano или mcedit в сеансе ssh на устройстве, либо залить его с помощью SCP. | ||
<!--T:112--> | |||
<pre> | <pre> | ||
root@wirenboard:~# mcedit /etc/wb-rules/rs485_cmd.js | root@wirenboard:~# mcedit /etc/wb-rules/rs485_cmd.js | ||
Строка 589: | Строка 686: | ||
<!--T:113--> | |||
4. Описываем в файле виртуальный девайс | 4. Описываем в файле виртуальный девайс | ||
<!--T:114--> | |||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
defineVirtualDevice("rs485_cmd", { | defineVirtualDevice("rs485_cmd", { | ||
Строка 604: | Строка 703: | ||
<!--T:115--> | |||
5. Перезапускаем wb-rules и проверяем работу | 5. Перезапускаем wb-rules и проверяем работу | ||
<!--T:116--> | |||
<pre> | <pre> | ||
root@wirenboard:~# /etc/init.d/wb-rules restart | root@wirenboard:~# /etc/init.d/wb-rules restart | ||
Строка 611: | Строка 712: | ||
</pre> | </pre> | ||
<!--T:117--> | |||
В логе не должно быть сообщений об ошибке (выход через control-c) | В логе не должно быть сообщений об ошибке (выход через control-c) | ||
<!--T:118--> | |||
В веб-интерфейсе в разделе Devices должно появиться новое устройство "Send custom command to RS-485 port". | В веб-интерфейсе в разделе Devices должно появиться новое устройство "Send custom command to RS-485 port". | ||
<!--T:119--> | |||
6. Добавим функцию для конфигурирования порта. | 6. Добавим функцию для конфигурирования порта. | ||
<!--T:120--> | |||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
function setup_port() { | function setup_port() { | ||
Строка 625: | Строка 730: | ||
} | } | ||
<!--T:121--> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
<!--T:122--> | |||
7. Опишем правила на включение и выключение переключателя | 7. Опишем правила на включение и выключение переключателя | ||
<!--T:123--> | |||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
defineRule("_rs485_switch_on", { | defineRule("_rs485_switch_on", { | ||
Строка 640: | Строка 748: | ||
}); | }); | ||
<!--T:124--> | |||
defineRule("_rs485_switch_off", { | defineRule("_rs485_switch_off", { | ||
asSoonAs: function () { | asSoonAs: function () { | ||
Строка 649: | Строка 758: | ||
}); | }); | ||
<!--T:125--> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
<!--T:126--> | |||
Обратите внимание на двойное экранирование. | Обратите внимание на двойное экранирование. | ||
Строка 657: | Строка 768: | ||
<!--T:127--> | |||
7. Собираем всё вместе | 7. Собираем всё вместе | ||
<!--T:128--> | |||
Полное содержимое файла с правилами: | Полное содержимое файла с правилами: | ||
<!--T:129--> | |||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
defineVirtualDevice("rs485_cmd", { | defineVirtualDevice("rs485_cmd", { | ||
Строка 673: | Строка 787: | ||
<!--T:130--> | |||
function setup_port() { | function setup_port() { | ||
runShellCommand("stty -F /dev/ttyNSC0 ospeed 9600 ispeed 9600 raw clocal -crtscts -parenb -echo cs8"); | runShellCommand("stty -F /dev/ttyNSC0 ospeed 9600 ispeed 9600 raw clocal -crtscts -parenb -echo cs8"); | ||
} | } | ||
<!--T:131--> | |||
defineRule("_rs485_switch_on", { | defineRule("_rs485_switch_on", { | ||
asSoonAs: function () { | asSoonAs: function () { | ||
Строка 686: | Строка 802: | ||
}); | }); | ||
<!--T:132--> | |||
defineRule("_rs485_switch_off", { | defineRule("_rs485_switch_off", { | ||
asSoonAs: function () { | asSoonAs: function () { | ||
Строка 695: | Строка 812: | ||
}); | }); | ||
<!--T:133--> | |||
setTimeout(setup_port, 1000); // запланировать выполнение setup_port() через 1 секунду после старта правил. | setTimeout(setup_port, 1000); // запланировать выполнение setup_port() через 1 секунду после старта правил. | ||
<!--T:134--> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Пользовательские поля в интерфейсе === | === Пользовательские поля в интерфейсе === <!--T:135--> | ||
<!--T:136--> | |||
Чтобы дать пользователю возможность вводить точные значения параметров (уставки) из интерфейса, можно воспользоваться [https://wirenboard.com/wiki/index.php/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D1%80%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%B8%D1%80%D1%83%D0%B5%D0%BC%D1%8B%D1%85_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%81%D0%BA%D0%B8%D1%85_%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9_%D0%B2_%D0%B2%D0%B5%D0%B1-%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81%D0%B5 инструкцией]. | Чтобы дать пользователю возможность вводить точные значения параметров (уставки) из интерфейса, можно воспользоваться [https://wirenboard.com/wiki/index.php/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D1%80%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%B8%D1%80%D1%83%D0%B5%D0%BC%D1%8B%D1%85_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%81%D0%BA%D0%B8%D1%85_%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9_%D0%B2_%D0%B2%D0%B5%D0%B1-%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81%D0%B5 инструкцией]. | ||
<!--T:137--> | |||
Более подробно и с примером - в [https://support.wirenboard.com/t/kak-na-wb5-wb6-sozdat-pole-dlya-vvoda-ustavok-i-peredat-znachenie-v-pravila/2180 теме на портале техподдержки]. | Более подробно и с примером - в [https://support.wirenboard.com/t/kak-na-wb5-wb6-sozdat-pole-dlya-vvoda-ustavok-i-peredat-znachenie-v-pravila/2180 теме на портале техподдержки]. | ||
=== Сложные правила с расписаниями === | === Сложные правила с расписаниями === <!--T:138--> | ||
<!--T:139--> | |||
Объект - продуктовый магазин. Различные системы магазина управляются по обратной связи от датчиков температуры и с учётом расписания работы магазина. | Объект - продуктовый магазин. Различные системы магазина управляются по обратной связи от датчиков температуры и с учётом расписания работы магазина. | ||
<!--T:140--> | |||
Для расписаний используются не cron-правила, а обёртка над ними. Обёртка включает и выключает правила, которые, в отличие от cron-правил, выполняются постоянно, будучи включенными. | Для расписаний используются не cron-правила, а обёртка над ними. Обёртка включает и выключает правила, которые, в отличие от cron-правил, выполняются постоянно, будучи включенными. | ||
<!--T:141--> | |||
Например, мы хотим, чтобы освещение было включено с 10 до 17ч. Обёртка (libschedule) будет выполнять правило "включить освещение" раз в минуту с 10 утра до 17 вечера. | Например, мы хотим, чтобы освещение было включено с 10 до 17ч. Обёртка (libschedule) будет выполнять правило "включить освещение" раз в минуту с 10 утра до 17 вечера. | ||
<!--T:142--> | |||
Это значит, что даже если контроллер работает с перерывами и пропустил время перехода между расписаниями (10 утра), то контроллер всё равно включит освещение при первой возможности. | Это значит, что даже если контроллер работает с перерывами и пропустил время перехода между расписаниями (10 утра), то контроллер всё равно включит освещение при первой возможности. | ||
<!--T:143--> | |||
lib_schedules.js: | lib_schedules.js: | ||
<!--T:144--> | |||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
global.__proto__.Schedules = {}; | global.__proto__.Schedules = {}; | ||
<!--T:145--> | |||
(function(Schedules) { // замыкание | (function(Schedules) { // замыкание | ||
function todayAt(now, hours, minutes) { | <!--T:146--> | ||
function todayAt(now, hours, minutes) { | |||
var date = new Date(now); | var date = new Date(now); | ||
// i.e. "today, at HH:MM". All dates are in UTC! | // i.e. "today, at HH:MM". All dates are in UTC! | ||
Строка 736: | Строка 865: | ||
function checkScheduleInterval(now, start_time, end_time) { | <!--T:147--> | ||
function checkScheduleInterval(now, start_time, end_time) { | |||
var start_date = todayAt(now, start_time[0], start_time[1]); | var start_date = todayAt(now, start_time[0], start_time[1]); | ||
var end_date = todayAt(now, end_time[0], end_time[1]); | var end_date = todayAt(now, end_time[0], end_time[1]); | ||
log("checkScheduleInterval {} {} {}".format(now, start_date, end_date)); | log("checkScheduleInterval {} {} {}".format(now, start_date, end_date)); | ||
if (end_date >= start_date) { | <!--T:148--> | ||
if (end_date >= start_date) { | |||
if ((now >= start_date) && (now < end_date)) { | if ((now >= start_date) && (now < end_date)) { | ||
return true; | return true; | ||
Строка 749: | Строка 880: | ||
// assuming they belong to a different days (e.g. today and tomorrow) | // assuming they belong to a different days (e.g. today and tomorrow) | ||
// option 1: what if it's now the day of "end" date? | <!--T:149--> | ||
// option 1: what if it's now the day of "end" date? | |||
// in this case the following is enough: | // in this case the following is enough: | ||
if (now < end_date) { | if (now < end_date) { | ||
Строка 755: | Строка 887: | ||
} | } | ||
// well, that seems not to be the case. ok, | <!--T:150--> | ||
// well, that seems not to be the case. ok, | |||
// option 2: it's the day of "start" date: | // option 2: it's the day of "start" date: | ||
if (now >= start_date) { | <!--T:151--> | ||
if (now >= start_date) { | |||
return true; | return true; | ||
} | } | ||
Строка 764: | Строка 898: | ||
return false; | return false; | ||
} | <!--T:152--> | ||
} | |||
function checkSchedule(schedule, now) { | <!--T:153--> | ||
function checkSchedule(schedule, now) { | |||
if (now == undefined) { | if (now == undefined) { | ||
now = new Date(); | now = new Date(); | ||
} | } | ||
for (var i = 0; i < schedule.intervals.length; ++i) { | <!--T:154--> | ||
for (var i = 0; i < schedule.intervals.length; ++i) { | |||
var item = schedule.intervals[i]; | var item = schedule.intervals[i]; | ||
if (checkScheduleInterval(now, item[0], item[1])) { | if (checkScheduleInterval(now, item[0], item[1])) { | ||
Строка 786: | Строка 923: | ||
}; | }; | ||
function addScheduleDevCronTasks(schedule) { | <!--T:155--> | ||
function addScheduleDevCronTasks(schedule) { | |||
for (var i = 0; i < schedule.intervals.length; ++i) { | for (var i = 0; i < schedule.intervals.length; ++i) { | ||
var interval = schedule.intervals[i]; | var interval = schedule.intervals[i]; | ||
Строка 804: | Строка 942: | ||
} | } | ||
function addScheduleAutoUpdCronTask(schedule) { | <!--T:156--> | ||
function addScheduleAutoUpdCronTask(schedule) { | |||
defineRule("_schedule_auto_upd_{}".format(schedule.name), { | defineRule("_schedule_auto_upd_{}".format(schedule.name), { | ||
when: cron("@every " + schedule.autoUpdate), | when: cron("@every " + schedule.autoUpdate), | ||
Строка 813: | Строка 952: | ||
} | } | ||
var _schedules = {}; | <!--T:157--> | ||
var _schedules = {}; | |||
Schedules.registerSchedule = function(schedule) { | <!--T:158--> | ||
Schedules.registerSchedule = function(schedule) { | |||
_schedules[schedule.name] = schedule; | _schedules[schedule.name] = schedule; | ||
}; | }; | ||
Schedules.initSchedules = function() { | <!--T:159--> | ||
Schedules.initSchedules = function() { | |||
var params = { | var params = { | ||
title: "Schedule Status", | title: "Schedule Status", | ||
Строка 825: | Строка 967: | ||
}; | }; | ||
for (var schedule_name in _schedules) { | <!--T:160--> | ||
for (var schedule_name in _schedules) { | |||
if (_schedules.hasOwnProperty(schedule_name)) { | if (_schedules.hasOwnProperty(schedule_name)) { | ||
var schedule = _schedules[schedule_name]; | var schedule = _schedules[schedule_name]; | ||
Строка 832: | Строка 975: | ||
}; | }; | ||
defineVirtualDevice("_schedules", params); | <!--T:161--> | ||
defineVirtualDevice("_schedules", params); | |||
for (var schedule_name in _schedules) { | <!--T:162--> | ||
for (var schedule_name in _schedules) { | |||
if (_schedules.hasOwnProperty(schedule_name)) { | if (_schedules.hasOwnProperty(schedule_name)) { | ||
var schedule = _schedules[schedule_name]; | var schedule = _schedules[schedule_name]; | ||
// setup cron tasks which updates the schedule dev status at schedule | <!--T:163--> | ||
// setup cron tasks which updates the schedule dev status at schedule | |||
// interval beginings and ends | // interval beginings and ends | ||
addScheduleDevCronTasks(schedule); | addScheduleDevCronTasks(schedule); | ||
// if needed, setup periodic task to trigger rules which use this schedule | <!--T:164--> | ||
// if needed, setup periodic task to trigger rules which use this schedule | |||
if (schedule.autoUpdate) { | if (schedule.autoUpdate) { | ||
addScheduleAutoUpdCronTask(schedule); | addScheduleAutoUpdCronTask(schedule); | ||
} | } | ||
// set schedule dev status as soon as possible at startup | <!--T:165--> | ||
// set schedule dev status as soon as possible at startup | |||
(function(schedule) { | (function(schedule) { | ||
setTimeout(function() { | setTimeout(function() { | ||
Строка 856: | Строка 1004: | ||
})(schedule); | })(schedule); | ||
}; | <!--T:166--> | ||
}; | |||
}; | }; | ||
}; | <!--T:167--> | ||
}; | |||
<!--T:168--> | |||
})(Schedules); | })(Schedules); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<!--T:169--> | |||
Пример правил, с использованием Schedules: | Пример правил, с использованием Schedules: | ||
<syntaxhighlight lang="ecmascript"> | <syntaxhighlight lang="ecmascript"> | ||
(function() { // замыкание | (function() { // замыкание | ||
defineAlias("countersTemperature", "wb-msw2_30/Temperature"); | <!--T:170--> | ||
defineAlias("countersTemperature", "wb-msw2_30/Temperature"); | |||
defineAlias("vegetablesTemperature", "wb-msw2_31/Temperature"); | defineAlias("vegetablesTemperature", "wb-msw2_31/Temperature"); | ||
defineAlias("heater1EnableInverted", "wb-mrm2-old_70/Relay 1"); | <!--T:171--> | ||
defineAlias("heater1EnableInverted", "wb-mrm2-old_70/Relay 1"); | |||
defineAlias("frontshopVentInverted", "wb-gpio/EXT1_R3A3"); | defineAlias("frontshopVentInverted", "wb-gpio/EXT1_R3A3"); | ||
Schedules.registerSchedule({ | <!--T:172--> | ||
Schedules.registerSchedule({ | |||
"name" : "signboard", // вывеска | "name" : "signboard", // вывеска | ||
"autoUpdate" : "1m", | "autoUpdate" : "1m", | ||
Строка 919: | Строка 1074: | ||
Schedules.initSchedules(); | Schedules.initSchedules(); | ||
// Вывеска и фасадное освещение | <!--T:173--> | ||
// Вывеска и фасадное освещение | |||
defineRule("signboardOnOff", { | defineRule("signboardOnOff", { | ||
when: function() { | when: function() { | ||
Строка 935: | Строка 1091: | ||
// Освещение торгового зала | <!--T:174--> | ||
// Освещение торгового зала | |||
defineRule("lightingFrontshopOnOff", { | defineRule("lightingFrontshopOnOff", { | ||
when: function() { | when: function() { | ||
Строка 947: | Строка 1104: | ||
// Вентиляция подсобного помещения | <!--T:175--> | ||
// Вентиляция подсобного помещения | |||
defineRule("ventBackstoreOnOff", { | defineRule("ventBackstoreOnOff", { | ||
when: function() { | when: function() { | ||
Строка 960: | Строка 1118: | ||
}); | }); | ||
// Освещение холодильных горок | <!--T:176--> | ||
// Освещение холодильных горок | |||
defineRule("lightingCoolingshelfsOnOff", { | defineRule("lightingCoolingshelfsOnOff", { | ||
when: function() { | when: function() { | ||
Строка 969: | Строка 1128: | ||
var on = dev._schedules.working_hours_15m; | var on = dev._schedules.working_hours_15m; | ||
// освещение в горках через нормально-закрытые реле (инвертировано) | <!--T:177--> | ||
// освещение в горках через нормально-закрытые реле (инвертировано) | |||
dev["wb-mrm2-old_60/Relay 1"] = !on; | dev["wb-mrm2-old_60/Relay 1"] = !on; | ||
dev["wb-mrm2-old_61/Relay 1"] = !on; | dev["wb-mrm2-old_61/Relay 1"] = !on; | ||
Строка 982: | Строка 1142: | ||
//Брендовые холодильники (пиво, лимонады) | <!--T:178--> | ||
//Брендовые холодильники (пиво, лимонады) | |||
defineRule("powerBrandFridgesOnOff", { | defineRule("powerBrandFridgesOnOff", { | ||
when: function() { | when: function() { | ||
Строка 996: | Строка 1157: | ||
// ========= Котлы и приточная вентиляция ТЗ =========== | <!--T:179--> | ||
// ========= Котлы и приточная вентиляция ТЗ =========== | |||
// обратная связь по температуре овощной зоны | // обратная связь по температуре овощной зоны | ||
// днём работает позиционный регулятор | <!--T:180--> | ||
// днём работает позиционный регулятор | |||
defineRule("heatersDayOff", { | defineRule("heatersDayOff", { | ||
when: function() { | when: function() { | ||
Строка 1010: | Строка 1173: | ||
}); | }); | ||
defineRule("heatersDayOn", { | <!--T:181--> | ||
defineRule("heatersDayOn", { | |||
when: function() { | when: function() { | ||
return (dev._schedules.heaters_schedule) && (vegetablesTemperature < 16.7); | return (dev._schedules.heaters_schedule) && (vegetablesTemperature < 16.7); | ||
Строка 1020: | Строка 1184: | ||
}); | }); | ||
// ночью работает позиционный регулятор | <!--T:182--> | ||
// ночью работает позиционный регулятор | |||
defineRule("heatersNightOff", { | defineRule("heatersNightOff", { | ||
when: function() { | when: function() { | ||
Строка 1031: | Строка 1196: | ||
}); | }); | ||
defineRule("heatersNightOn", { | <!--T:183--> | ||
defineRule("heatersNightOn", { | |||
when: function() { | when: function() { | ||
return (!dev._schedules.heaters_schedule) && (vegetablesTemperature < 11.3); | return (!dev._schedules.heaters_schedule) && (vegetablesTemperature < 11.3); | ||
Строка 1042: | Строка 1208: | ||
// приточная и вытяжная вентиляция принудительно выключены | <!--T:184--> | ||
// приточная и вытяжная вентиляция принудительно выключены | |||
defineRule("ventFrontshopAlwaysOff", { | defineRule("ventFrontshopAlwaysOff", { | ||
Строка 1055: | Строка 1222: | ||
// ================== Кассовая зона ================= | // ================== Кассовая зона ================= | ||
// в кассовой зоне в рабочее время температура поддерживается кондиционерами (позиционный регулятор) | <!--T:185--> | ||
// в кассовой зоне в рабочее время температура поддерживается кондиционерами (позиционный регулятор) | |||
defineRule("countersACOn", { | <!--T:186--> | ||
defineRule("countersACOn", { | |||
when: function() { | when: function() { | ||
return (dev._schedules.working_hours_15m) && (countersTemperature < 17.7); | return (dev._schedules.working_hours_15m) && (countersTemperature < 17.7); | ||
Строка 1067: | Строка 1236: | ||
}); | }); | ||
// в нерабочее время кондиционер выключен | <!--T:187--> | ||
// в нерабочее время кондиционер выключен | |||
defineRule("countersACOff", { | defineRule("countersACOff", { | ||
when: function() { | when: function() { | ||
Строка 1078: | Строка 1248: | ||
}); | }); | ||
// =============== Овощная зона ============== | <!--T:188--> | ||
// =============== Овощная зона ============== | |||
// Охлаждение овощей кондиционером только при температуре воздуха выше 18.5C | // Охлаждение овощей кондиционером только при температуре воздуха выше 18.5C | ||
defineRule("acVegOn", { | <!--T:189--> | ||
defineRule("acVegOn", { | |||
when: function() { | when: function() { | ||
return vegetablesTemperature >= 18.5 | return vegetablesTemperature >= 18.5 | ||
Строка 1091: | Строка 1263: | ||
}); | }); | ||
defineRule("acVegOff", { | <!--T:190--> | ||
defineRule("acVegOff", { | |||
when: function() { | when: function() { | ||
return vegetablesTemperature < 17.8 | return vegetablesTemperature < 17.8 | ||
Строка 1105: | Строка 1278: | ||
== Полное описание возможностей движка правил == | == Полное описание возможностей движка правил == <!--T:191--> | ||
<!--T:192--> | |||
Самое полное описание движка правил: https://github.com/contactless/wb-rules/blob/master/README.md | Самое полное описание движка правил: https://github.com/contactless/wb-rules/blob/master/README.md | ||
== Новые возможности последних версий == | == Новые возможности последних версий == <!--T:193--> | ||
<!--T:194--> | |||
* [[Special:MyLanguage/Движок_правил_wb-rules_1.7|Движок правил wb-rules 1.7]] | * [[Special:MyLanguage/Движок_правил_wb-rules_1.7|Движок правил wb-rules 1.7]] | ||
== В разработке == | == В разработке == <!--T:195--> | ||
<!--T:196--> | |||
Описание возможностей будущих версий движка правил можно прочесть здесь: | Описание возможностей будущих версий движка правил можно прочесть здесь: | ||
* [[Special:MyLanguage/Движок_правил_wb-rules_2.0|Движок правил wb-rules 2.0]] | * [[Special:MyLanguage/Движок_правил_wb-rules_2.0|Движок правил wb-rules 2.0]] | ||
</translate> | </translate> |
правки