|
Метка: новое перенаправление |
(не показаны 53 промежуточные версии 9 участников) |
Строка 1: |
Строка 1: |
| [[File:Wb rules demo.png|400px|thumb|right|Редактирование правил в веб-интерфейсе]] | | #REDIRECT [[Wb-rules]] |
| Для контроллера можно писать правила, например: "Если температура датчика меньше 18°С, включи нагреватель". Правила создаются через [[Веб-интерфейс Wiren Board|веб-интерфейс]] и пишутся на простом языке, похожем на Javascript.
| |
| | |
| Недавно вышло крупное обновление движка правил, ознакомиться с которым можно [[Движок_правил_wb-rules_2.0|по ссылке]].
| |
| | |
| Самое полное описание движка правил: https://github.com/contactless/wb-rules
| |
| | |
| == Как создавать и редактировать правила ==
| |
| *Список файлов с правилами находится на странице ''Scripts'' веб-интерфейса.
| |
| *Нажмите на название файла, чтобы открыть его для редактирования.
| |
| **Чтобы создать новый файл, нажмите на пункт ''New...'', вверху введите название скрипта (используйте для названия только латинские буквы и цифры, в качестве расширения укажите ''.js''), в основное поле введите текст скрипта, затем нажмите кнопку ''Save'' вверху.
| |
| *Правило начинает работать автоматически после нажатия кнопки ''Save'', если в нём нет ошибок (смотрите ниже).
| |
| Примечания:
| |
| #Файлы с правилами хранятся на контроллере в виде обычных текстовых файлов в папке <code>/etc/wb-rules/</code>, поэтому [[Просмотр файлов контроллера с компьютера|их можно редактировать и загружать напрямую с компьютера]].
| |
| #Правила исполняются сервисом ''wb-rules'', документацию по нему смотрите [https://github.com/contactless/wb-rules странице сервиса в Github].
| |
| | |
| == Пишем первое правило ==
| |
| [[File:Web-scripts-rule1.png|400px|thumb|Правило для управления обогревателем, записанное через веб-интерфейс]]
| |
| | |
| Правила бывают двух типов - непосредственно правила (начинаются со слов ''defineRule'') и виртуальные устройства (начинаются со слов ''defineVirtualDevice''). Виртуальные устройства - это появляющиеся в веб-интерфейсе новые элементы управления - например, кнопка-выключатель, которая на самом деле выключает два устройства одновременно. Она не привязана напрямую ни к какому физическому устройству, а действия при её нажатии определяются написанным вами скриптом.
| |
| | |
| Любое количество разных правил можно хранить в одном файле. Обычно в одном файле хранятся правила, отвечающие за близкие функции.
| |
| | |
| === Первое правило ===
| |
| | |
| Для начала разберём простое правило - при превышении температуры выключи обогреватель. Температуру получаем с датчика [[1-Wire]], обогреватель подключён к Реле 1 внешнего релейного модуля [[WB-MRM2]].
| |
| <syntaxhighlight lang="ecmascript">
| |
| | |
| defineRule("heater_control", { //название правила - "контроль обогревателя", может быть произвольным
| |
| whenChanged: "wb-w1/28-0115a48fcfff", //при изменении состояния датчика 1-Wire с идентификатором 28-0115a48fcfff
| |
| then: function (newValue, devName, cellName) { //выполняй следующие действия
| |
| if ( newValue > 30) { //если температура датчика больше 30 градусов
| |
| dev["wb-mrm2_130"]["Relay 1"] = 0; //установи Реле 1 модуля WB-MRM2 с адресом 130 в состояние "выключено"
| |
| } else {
| |
| dev["wb-mrm2_130"]["Relay 1"] = 1; //установи Реле 1 модуля WB-MRM2 с адресом 130 в состояние "включено"
| |
| }
| |
| }
| |
| });
| |
| | |
| </syntaxhighlight>
| |
| *Первая строка - кодовое слово ''defineRule'' и название правила
| |
| *Вторая строка - кодовое слово для определения, когда выполняется правило, - ''whenChanged'' - "при изменении параметра", далее название параметра, при изменении которого запустится правило - температура с датчика 1-Wire. Название параметра записывается в виде "Device/Control", где названия ''Device'' и ''Control'' для каждого параметра можно найти на странице ''Settings'' веб-интерфейса в таблице ''MQTT Channels''.
| |
| *Третья строка - начало функции, которая будет исполняться
| |
| *Затем идёт условие - "если значение температуры больше порогового, то ...". Значение параметра записывается в виде ''dev[Device][Control]'' - заметьте, оно отличается от вида записи параметра, при изменении которого запускается правило, потому что там речь идёт о ''параметре'', а здесь - о ''значении'' того же параметра.
| |
| *Затем мы выставляем значения для реле в каждом случае - ''0'' - "выключено", ''1'' - "включено". Названия ''Device'' и ''Control'' для реле смотрим всё в той же таблице ''MQTT Channels'' на странице ''Settings'' веб-интерфейса.
| |
| | |
| === Первое правило с виртуальным устройством ===
| |
| Создаём виртуальный переключатель, при нажатии на который переключаются сразу два реле.
| |
| | |
| <syntaxhighlight lang="ecmascript">
| |
| defineVirtualDevice("switch_both", {
| |
| title: "Switch both relays",
| |
| cells: {
| |
| enabled: {
| |
| type: "switch",
| |
| value: false
| |
| },
| |
| }
| |
| });
| |
| | |
| defineRule("control_both", {
| |
| whenChanged: "switch_both/enabled",
| |
| then: function (newValue, devName, cellName) {
| |
| dev["wb-mrm2_130"]["Relay 1"] = newValue;
| |
| dev["wb-mrm2_130"]["Relay 2"] = newValue;
| |
| }
| |
| });
| |
| </syntaxhighlight>
| |
| | |
| === Пишем сложные правила ===
| |
| Чтобы начать писать сложные правила, нужно посмотреть примеры правил и полную документацию по движку правил:
| |
| #Примеры правил:
| |
| #* на этой же странице ниже;
| |
| #* в [http://forums.contactless.ru/t/dvizhok-pravil-primery-koda/483 специальной теме на нашем форуме ].
| |
| #[https://github.com/contactless/wb-rules Полное описание движка правил].
| |
| | |
| == Примеры правил ==
| |
| === Слежение за контролом ===
| |
| | |
| Это простейшее правило следит за контролом и устанавливает другой контрол в такое же состояние.
| |
| | |
| Например правило может включать сирену и лампу, если датчик движения заметил движение.
| |
| | |
| В примере датчик движения подключен к входу "сухой контакт", контрол типа "switch". Сирена подключена к встроеному реле Wiren Board, а лампа - через релейный блок по Modbus. Когда вход типа "сухой контакт" (выход датчика движения) замкнут, то на лампу и реле подаётся "1", когда выключен - "0".
| |
| | |
| | |
| Правило срабатывает каждый раз при изменении значения контрола "D1_IN" у устройства "wb-gpio". В код правила передаётся новое значение этого контрола в виде переменной newValue.
| |
| | |
| <syntaxhighlight lang="ecmascript">
| |
| | |
| defineRule("motion_detector", {
| |
| whenChanged: "wb-gpio/D1_IN",
| |
| then: function (newValue, devName, cellName) {
| |
| dev["wb-gpio"]["Relay_2"] = newValue;
| |
| dev["wb-mrm2_6"]["Relay 1"] = newValue;
| |
| | |
| }
| |
| });
| |
| | |
| </syntaxhighlight>
| |
| | |
| | |
| То же самое, но с виртуальным девайсом в качестве источника событий. Пример использования: сценарная кнопка, которая включает/выключает сирену и лампочку.
| |
| | |
| <syntaxhighlight lang="ecmascript">
| |
| defineVirtualDevice("simple_test", {
| |
| title: "Simple switch",
| |
| cells: {
| |
| enabled: {
| |
| type: "switch",
| |
| value: false
| |
| },
| |
| }
| |
| });
| |
| | |
| | |
| defineRule("simple_switch", {
| |
| whenChanged: "simple_test/enabled",
| |
| then: function (newValue, devName, cellName) {
| |
| dev["wb-gpio"]["Relay_2"] = newValue;
| |
| dev["wb-mrm2_6"]["Relay 1"] = newValue;
| |
| | |
| }
| |
| });
| |
| | |
| </syntaxhighlight>
| |
| | |
| === Детектор движения c таймаутом ===
| |
| | |
| На вход D2 подключен детектор движения с выходом типа "сухой контакт", который замыкает D2 и GND при обнаружении движения.
| |
| При этом, на канале "wb-gpio/D2_IN" появляется статус "1".
| |
| | |
| Правило включает свет при обнаружении движения и выключает свет, спустя 30 секунд после пропадания сигнала с датчика движения.
| |
| | |
| Освещение подключено через встроенное реле, канал wb-gpio/Relay_1.
| |
| | |
| <syntaxhighlight lang="ecmascript">
| |
| | |
| var motion_timer_1_timeout_ms = 30 * 1000;
| |
| var motion_timer_1_id = null;
| |
| | |
| defineRule("motion_detector_1", {
| |
| whenChanged: "wb-gpio/D2_IN",
| |
| then: function (newValue, devName, cellName) {
| |
| if (newValue) {
| |
| dev["wb-gpio"]["Relay_1"] = 1;
| |
| | |
| if (motion_timer_1_id) {
| |
| clearTimeout(motion_timer_1_id);
| |
| }
| |
|
| |
| motion_timer_1_id = setTimeout(function () {
| |
| dev["wb-gpio"]["Relay_1"] = 0;
| |
| motion_timer_1_id = null;
| |
| }, motion_timer_1_timeout_ms);
| |
| }
| |
| }
| |
| });
| |
| | |
| </syntaxhighlight>
| |
| | |
| === Создание однотипных правил ===
| |
| Если таких детекторов движения нужно несколько, то, чтобы не копировать код, можно обернуть создание правила и переменных в функцию:
| |
| | |
| <syntaxhighlight lang="ecmascript">
| |
| function makeMotionDetector(name, timeout_ms, detector_control, relay_control) {
| |
| var motion_timer_id = null;
| |
| defineRule(name, {
| |
| whenChanged: "wb-gpio/" + detector_control,
| |
| then: function(newValue, devName, cellName) {
| |
| if (!newValue) {
| |
| dev["wb-gpio"][relay_control] = 1;
| |
| if (motion_timer_id) {
| |
| clearTimeout(motion_timer_id);
| |
| }
| |
| | |
| motion_timer_id = setTimeout(function() {
| |
| dev["wb-gpio"][relay_control] = 0;
| |
| motion_timer_id = null;
| |
| }, timeout_ms);
| |
| }
| |
| }
| |
| });
| |
| }
| |
| | |
| makeMotionDetector("motion_detector_1", 20000, "EXT1_DR1", "EXT2_R3A1");
| |
| makeMotionDetector("motion_detector_2", 10000, "EXT1_DR2", "EXT2_R3A2");
| |
| makeMotionDetector("motion_detector_3", 10000, "EXT1_DR3", "EXT2_R3A3");
| |
| </syntaxhighlight>
| |
| | |
| === Активация правила только в определённое время ===
| |
| | |
| Правило как в предыдущем разделе, но выполняется только с 9:30 до 17:10 по UTC.
| |
| | |
| <syntaxhighlight lang="ecmascript">
| |
| var motion_timer_1_timeout_ms = 5 * 1000;
| |
| var motion_timer_1_id = null;
| |
|
| |
| defineRule("motion_detector_1", {
| |
| whenChanged: "wb-gpio/A1_IN",
| |
| then: function (newValue, devName, cellName) {
| |
| var date = new Date();
| |
| | |
| // time point marking the beginning of the interval
| |
| // i.e. "today, at HH:MM". All dates are in UTC!
| |
| var date_start = new Date(date);
| |
| date_start.setHours(9);
| |
| date_start.setMinutes(30);
| |
| | |
| // time point marking the end of the interval
| |
| var date_end = new Date(date);
| |
| date_end.setHours(17);
| |
| date_end.setMinutes(10);
| |
|
| |
| // if time is between 09:30 and 17:10 UTC
| |
| if ((date > date_start) && (date < date_end)) {
| |
| if (newValue) {
| |
| dev["wb-gpio"]["EXT1_R3A1"] = 1;
| |
|
| |
| if (motion_timer_1_id) {
| |
| clearTimeout(motion_timer_1_id);
| |
| }
| |
|
| |
| motion_timer_1_id = setTimeout(function () {
| |
| dev["wb-gpio"]["EXT1_R3A1"] = 0;
| |
| motion_timer_1_id = null;
| |
| }, motion_timer_1_timeout_ms);
| |
| }
| |
| }
| |
| }
| |
| });
| |
| </syntaxhighlight>
| |
| | |
| === Роллеты ===
| |
| | |
| Одно реле включает двигатель, поднимающий шторы, второе реле - включает двигатель, опускающий шторы.
| |
| Правило следит за тем, чтобы оба реле не были включены одновременно.
| |
| | |
| Кроме этого, правило отключает двигатели спустя заданное время после включения.
| |
| | |
| <syntaxhighlight lang="ecmascript">
| |
| (function() { //don't touch this line
| |
|
| |
| var suffix = "1"; // must be different in different JS files
| |
|
| |
| var relay_up_device = "lc103_4";
| |
| var relay_up_control = "Relay 1";
| |
| | |
| var relay_down_device = "lc103_4";
| |
| var relay_down_control = "Relay 2";
| |
| | |
| var timeout_s = 15;
| |
|
| |
| // End of settings
| |
|
| |
|
| |
| var relay_up_timer_id = null;
| |
| var relay_down_timer_id = null;
| |
|
| |
| defineRule( "roller_shutter_up_on" + suffix, {
| |
| asSoonAs: function() {
| |
| return dev[relay_up_device][relay_up_control];
| |
| },
| |
| then: function () {
| |
| if (relay_up_timer_id) {
| |
| relay_up_timer_id = clearTimeout(relay_up_timer_id);
| |
| };
| |
| | |
| relay_up_timer_id = setTimeout(function() {
| |
| return dev[relay_up_device][relay_up_control] = 0;
| |
| }, timeout_s * 1000);
| |
| }
| |
| });
| |
| | |
| defineRule("roller_shutter_down_on" + suffix, {
| |
| asSoonAs: function() {
| |
| return dev[relay_down_device][relay_down_control];
| |
| },
| |
| then: function () {
| |
| if (relay_down_timer_id) {
| |
| relay_down_timer_id = clearTimeout(relay_down_timer_id);
| |
| };
| |
|
| |
| relay_down_timer_id = setTimeout(function() {
| |
| dev[relay_down_device][relay_down_control] = 0;
| |
| }, timeout_s * 1000);
| |
| }
| |
| });
| |
| | |
| defineRule("roller_shutter_both_on" + suffix, {
| |
| asSoonAs: function() {
| |
| return dev[relay_up_device][relay_up_control] && dev[relay_down_device][relay_down_control];
| |
| },
| |
| then: function () {
| |
| if (relay_up_timer_id) {
| |
| relay_up_timer_id = clearTimeout(relay_up_timer_id);
| |
| };
| |
| | |
| if (relay_down_timer_id) {
| |
| relay_down_timer_id = clearTimeout(relay_down_timer_id);
| |
| };
| |
| | |
|
| |
| dev[relay_up_device][relay_up_control] = 0;
| |
| dev[relay_down_device][relay_down_control] = 0;
| |
| log("Both roller shutter relays on, switching them off");
| |
| }
| |
| });
| |
| })();
| |
| </syntaxhighlight>
| |
| | |
| | |
| | |
| Более старая версия того же сценария демонстрирует использование alias-ов:
| |
| <syntaxhighlight lang="ecmascript">
| |
| | |
| (function() {
| |
| defineAlias("relay_up_1", "lc103_4/Relay 1");
| |
| defineAlias("relay_down_1", "lc103_4/Relay 2");
| |
| var timeout_s = 15;
| |
| | |
| defineRule("roller_shutter_1_up_on", {
| |
| asSoonAs: function() {
| |
| return relay_up_1;
| |
| },
| |
| then: function () {
| |
| setTimeout(function() {
| |
| relay_up_1 = 0;
| |
| }, timeout_s * 1000);
| |
| }
| |
| });
| |
| | |
| defineRule("roller_shutter_1_down_on", {
| |
| asSoonAs: function() {
| |
| return relay_down_1;
| |
| },
| |
| then: function () {
| |
| setTimeout(function() {
| |
| relay_down_1 = 0;
| |
| }, timeout_s * 1000);
| |
| }
| |
| });
| |
| | |
| defineRule("roller_shutter_1_both_on", {
| |
| asSoonAs: function() {
| |
| return relay_up_1 && relay_down_1;
| |
| },
| |
| then: function () {
| |
| relay_up_1 = 0;
| |
| relay_down_1 = 0;
| |
| log("Both roller shutter relays on, switching them off");
| |
| }
| |
| });
| |
| })();
| |
| | |
| </syntaxhighlight>
| |
| | |
| === Системные правила ===
| |
| Некоторые правила поставляются с системой правил по умолчанию в пакете wb-rules-system.
| |
| | |
| Полный список правил [https://github.com/contactless/wb-rules-system/tree/master/rules в репозитории].
| |
| | |
| Некоторые примеры:
| |
| | |
| ==== Правило для пищалки ====
| |
| [https://github.com/contactless/wb-rules-system/blob/master/rules/buzzer.js Правило] создаёт виртуальное устройство buzzer с ползунками для регулировки громкости и частоты, а также кнопкой включения звука.
| |
| | |
| | |
| <syntaxhighlight lang="ecmascript">
| |
| defineVirtualDevice("buzzer", {
| |
| title: "Buzzer", //
| |
| | |
| cells: {
| |
| frequency : {
| |
| type : "range",
| |
| value : 3000,
| |
| max : 7000,
| |
| },
| |
| volume : {
| |
| type : "range",
| |
| value : 10,
| |
| max : 100,
| |
| },
| |
| enabled : {
| |
| type : "switch",
| |
| value : false,
| |
| },
| |
| }
| |
| });
| |
| | |
| | |
| // setup pwm2
| |
| runShellCommand("echo 2 > /sys/class/pwm/pwmchip0/export");
| |
| | |
| | |
| | |
| function _buzzer_set_params() {
| |
| var period = parseInt(1.0 / dev.buzzer.frequency * 1E9);
| |
| var duty_cycle = parseInt(dev.buzzer.volume * 1.0 / 100 * period * 0.5);
| |
| | |
| | |
| runShellCommand("echo " + period + " > /sys/class/pwm/pwmchip0/pwm2/period");
| |
| runShellCommand("echo " + duty_cycle + " > /sys/class/pwm/pwmchip0/pwm2/duty_cycle");
| |
| };
| |
| | |
| | |
| defineRule("_system_buzzer_params", {
| |
| whenChanged: [
| |
| "buzzer/frequency",
| |
| "buzzer/volume",
| |
| ],
| |
| | |
| then: function (newValue, devName, cellName) {
| |
| if ( dev.buzzer.enabled) {
| |
| _buzzer_set_params();
| |
| }
| |
| }
| |
| });
| |
| | |
| | |
| defineRule("_system_buzzer_onof", {
| |
| whenChanged: "buzzer/enabled",
| |
| then: function (newValue, devName, cellName) {
| |
| if ( dev.buzzer.enabled) {
| |
| _buzzer_set_params();
| |
| runShellCommand("echo 1 > /sys/class/pwm/pwmchip0/pwm2/enable");
| |
| } else {
| |
| runShellCommand("echo 0 > /sys/class/pwm/pwmchip0/pwm2/enable");
| |
| }
| |
| }
| |
| });
| |
| | |
| | |
| | |
| </syntaxhighlight>
| |
| | |
| ==== Правило для статуса питания ====
| |
| | |
| [https://github.com/contactless/wb-rules-system/blob/master/rules/power_status.js Правило] создаёт виртуальное устройство, которое сообщает текущий статус питания. В качестве входных данных используется два канала АЦП: измерение напряжения на аккумуляторе и измерение входного напряжения.
| |
| | |
| Реализована следующая логика:
| |
| | |
| 1. Если входное напряжение меньше напряжение на аккумуляторе, то значит плата питается от аккумулятора. В этом случае, также отображается 0V в качестве входного напряжения.
| |
| | |
| 2. Если входное напряжение больше напряжения на аккумуляторе, то плата работает от внешнего источника питания. В качестве входонго напряжения отображается измерение с канала Vin.
| |
| | |
| | |
| Для иллюстрации правила используют два разных способа срабатывания: по изменению значения контрола (правило _system_track_vin) и по изменению значения выражения (два других).
| |
| | |
| <syntaxhighlight lang="ecmascript">
| |
| | |
| defineVirtualDevice("power_status", {
| |
| title: "Power status", //
| |
| | |
| cells: {
| |
| 'working on battery' : {
| |
| type : "switch",
| |
| value : false,
| |
| readonly : true
| |
| },
| |
| 'Vin' : {
| |
| type : "voltage",
| |
| value : 0
| |
| }
| |
| | |
| | |
| }
| |
| });
| |
| | |
| | |
| | |
| defineRule("_system_track_vin", {
| |
| whenChanged: "wb-adc/Vin",
| |
| then: function() {
| |
| if (dev["wb-adc"]["Vin"] < dev["wb-adc"]["BAT"] ) {
| |
| dev["power_status"]["Vin"] = 0;
| |
| } else {
| |
| dev["power_status"]["Vin"] = dev["wb-adc"]["Vin"] ;
| |
| }
| |
| }
| |
| });
| |
| | |
| | |
| | |
| defineRule("_system_dc_on", {
| |
| asSoonAs: function () {
| |
| return dev["wb-adc"]["Vin"] > dev["wb-adc"]["BAT"];
| |
| },
| |
| then: function () {
| |
| dev["power_status"]["working on battery"] = false;
| |
| }
| |
| });
| |
| | |
| defineRule("_system_dc_off", {
| |
| asSoonAs: function () {
| |
| return dev["wb-adc"]["Vin"] <= dev["wb-adc"]["BAT"];
| |
| },
| |
| then: function () {
| |
| dev["power_status"]["working on battery"] = true;
| |
| }
| |
| });
| |
| | |
| </syntaxhighlight>
| |
| | |
| === Отправка команд по RS-485 ===
| |
| | |
| Для примера отправим команду устройству на порт ''/dev/ttyNSC0'' (соответствует аппаратному порту RS-485-ISO на [[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 в документации].
| |
| | |
| С помощью движка правил создадим виртуальное устройство с контролом типа switch (переключатель).
| |
| | |
| При включении переключателя будем отправлять команду (уст. Яркость кан. 00=0xff) для Uniel UCH-M141:
| |
| <pre>
| |
| FF FF 0A 01 FF 00 00 0A
| |
| </pre>
| |
| | |
| | |
| При выключении переключателя будем отправлять команду (уст. Яркость кан. 00=0x00) для Uniel UCH-M141:
| |
| <pre>
| |
| FF FF 0A 01 00 00 00 0B
| |
| </pre>
| |
| | |
| | |
| | |
| | |
| | |
| 1. Настройка порта
| |
| | |
| Для настройки порта /dev/ttyNSC0 на скорость 9600 надо выполнить следующую команду
| |
| | |
| <pre>
| |
| stty -F /dev/ttyNSC0 ospeed 9600 ispeed 9600 raw clocal -crtscts -parenb -echo cs8
| |
| </pre>
| |
| | |
| 2. Отправка команды
| |
| | |
| Отправка данных делается следующей шелл-командой:
| |
| | |
| <pre>
| |
| /usr/bin/printf '\xFF\xFF\x0A\x01\xD1\x06\x00\xE2' >/dev/ttyNSC0
| |
| </pre>
| |
| где "\xFF\xFF\x0A\x01\xD1\x06\x00\xE2" - это запись команды "FF FF 0A 01 D1 06 00 E2".
| |
| | |
| | |
| 3. Создадим в движке правил новый файл с правилами <code>/etc/wb-rules/rs485_cmd.js</code>
| |
| | |
| Файл можно редактировать с помощью vim, nano или mcedit в сеансе ssh на устройстве, либо залить его с помощью SCP.
| |
| | |
| <pre>
| |
| root@wirenboard:~# mcedit /etc/wb-rules/rs485_cmd.js
| |
| </pre>
| |
| | |
| | |
| 4. Описываем в файле виртуальный девайс
| |
| | |
| <syntaxhighlight lang="ecmascript">
| |
| defineVirtualDevice("rs485_cmd", {
| |
| title: "Send custom command to RS-485 port",
| |
| cells: {
| |
| enabled: {
| |
| type: "switch",
| |
| value: false
| |
| },
| |
| }
| |
| });
| |
| </syntaxhighlight>
| |
| | |
| | |
| 5. Перезапускаем wb-rules и проверяем работу
| |
| | |
| <pre>
| |
| root@wirenboard:~# /etc/init.d/wb-rules restart
| |
| root@wirenboard:~# tail -f /var/log/messages
| |
| </pre>
| |
| | |
| В логе не должно быть сообщений об ошибке (выход через control-c)
| |
| | |
| | |
| В веб-интерфейсе в разделе Devices должно появиться новое устройство "Send custom command to RS-485 port".
| |
| | |
| | |
| 6. Добавим функцию для конфигурирования порта.
| |
| | |
| | |
| <syntaxhighlight lang="ecmascript">
| |
| function setup_port() {
| |
| runShellCommand("stty -F /dev/ttyNSC0 ospeed 9600 ispeed 9600 raw clocal -crtscts -parenb -echo cs8");
| |
| }
| |
| | |
| </syntaxhighlight>
| |
| | |
| | |
| 7. Опишем правила на включение и выключение переключателя
| |
| | |
| <syntaxhighlight lang="ecmascript">
| |
| defineRule("_rs485_switch_on", {
| |
| asSoonAs: function () {
| |
| return dev.rs485_cmd.enabled;
| |
| },
| |
| then: function() {
| |
| runShellCommand("/usr/bin/printf '\\xff\\xff\\x0a\\x01\\xff\\x00\\x00\\x0a' > /dev/ttyNSC0");
| |
| }
| |
| });
| |
| | |
| defineRule("_rs485_switch_off", {
| |
| asSoonAs: function () {
| |
| return !dev.rs485_cmd.enabled;
| |
| },
| |
| then: function() {
| |
| runShellCommand("/usr/bin/printf '\\xff\\xff\\x0a\\x01\\x00\\x00\\x00\\x0b' >/dev/ttyNSC0");
| |
| }
| |
| });
| |
| | |
| </syntaxhighlight>
| |
| | |
| | |
| Обратите внимание на двойное экранирование.
| |
| | |
| | |
| | |
| | |
| 7. Собираем всё вместе
| |
| | |
| Полное содержимое файла с правилами:
| |
| | |
| <syntaxhighlight lang="ecmascript">
| |
| defineVirtualDevice("rs485_cmd", {
| |
| title: "Send custom command to RS-485 port",
| |
| cells: {
| |
| enabled: {
| |
| type: "switch",
| |
| value: false
| |
| },
| |
| }
| |
| });
| |
| | |
| | |
| function setup_port() {
| |
| runShellCommand("stty -F /dev/ttyNSC0 ospeed 9600 ispeed 9600 raw clocal -crtscts -parenb -echo cs8");
| |
| }
| |
| | |
| defineRule("_rs485_switch_on", {
| |
| asSoonAs: function () {
| |
| return dev.rs485_cmd.enabled;
| |
| },
| |
| then: function() {
| |
| runShellCommand("/usr/bin/printf '\\xff\\xff\\x0a\\x01\\xff\\x00\\x00\\x0a' > /dev/ttyNSC0");
| |
| }
| |
| });
| |
| | |
| defineRule("_rs485_switch_off", {
| |
| asSoonAs: function () {
| |
| return !dev.rs485_cmd.enabled;
| |
| },
| |
| then: function() {
| |
| runShellCommand("/usr/bin/printf '\\xff\\xff\\x0a\\x01\\x00\\x00\\x00\\x0b' >/dev/ttyNSC0");
| |
| }
| |
| });
| |
| | |
| setTimeout(setup_port, 1000); // запланировать выполненеи setup_port() через 1 секунду после старта правил.
| |
| | |
| </syntaxhighlight>
| |