Rule Examples/en: различия между версиями

Обновление для соответствия новой версии исходной страницы.
(Новая страница: «To process clicks, you need to track the state of the counter of the desired type of click on the controller and, when it changes, perform an action.»)
(Обновление для соответствия новой версии исходной страницы.)
 
(не показаны 73 промежуточные версии 2 участников)
Строка 1: Строка 1:
{{DISPLAYTITLE: Примеры правил}}
<languages/>
<languages/>
{{DISPLAYTITLE: Rule Examples}}
=== Control tracking ===
=== Control tracking ===


Строка 7: Строка 8:
For example, a rule can turn on a siren and a lamp if a motion sensor detects movement.  
For example, a rule can turn on a siren and a lamp if a motion sensor detects movement.  


In the example, the motion sensor is connected to the "dry contact" input, control type "switch". The siren is connected to the built-in Wiren Board relay, and the lamp is connected to the relay box via Modbus. When the "dry contact" input (motion sensor output) is closed, "1" is supplied to the lamp and the relay, and "0" when it is off.
In the example, the motion sensor is connected to the «dry contact» input, control type «switch». The siren is connected to the built-in Wiren Board relay, and the lamp is connected to the relay box via Modbus. When the «dry contact» input (motion sensor output) is closed, «1» is supplied to the lamp and the relay, and «0» when it is off.


The rule is triggered every time the control value "D1_IN" of the device "wb-gpio" is changed. The new value of this control is passed to the rule code as a variable newValue.
The rule is triggered every time the control value «D1_IN» of the device «wb-gpio» is changed. The new value of this control is passed to the rule code as a variable newValue.


<syntaxhighlight lang="ecmascript">
<syntaxhighlight lang="ecmascript">
Строка 16: Строка 17:
   whenChanged: "wb-gpio/D1_IN",
   whenChanged: "wb-gpio/D1_IN",
   then: function (newValue, devName, cellName) {
   then: function (newValue, devName, cellName) {
dev["wb-gpio"]["Relay_2"] = newValue;
dev["wb-gpio/Relay_2"] = newValue;
dev["wb-mrm2_6"]["Relay 1"] = newValue;
dev["wb-mrm2_6/Relay 1"] = newValue;


   }
   }
Строка 40: Строка 41:
   whenChanged: "simple_test/enabled",
   whenChanged: "simple_test/enabled",
   then: function (newValue, devName, cellName) {
   then: function (newValue, devName, cellName) {
dev["wb-gpio"]["Relay_2"] = newValue;
dev["wb-gpio/Relay_2"] = newValue;
dev["wb-mrm2_6"]["Relay 1"] = newValue;
dev["wb-mrm2_6/Relay 1"] = newValue;


   }
   }
Строка 49: Строка 50:
=== Motion detection with timeout ===
=== Motion detection with timeout ===


A motion detector with a "dry contact" output is connected to input D2. When motion is detected, it shorts D2 and GND and status "1" appears on the corresponding <code>wb-gpio/D2_IN</code> channel.
A motion detector with a «dry contact» output is connected to input D2. When motion is detected, it shorts D2 and GND and status «1» appears on the corresponding <code>wb-gpio/D2_IN</code> channel.


The lighting is connected via a built-in relay corresponding to the <code>wb-gpio/Relay_1</code> channel.
The lighting is connected via a built-in relay corresponding to the <code>wb-gpio/Relay_1</code> channel.


The rule works like this:
The rule works like this:
* when movement appears, the light turns on. If a thirty-second "off" timer was previously started, this timer is disabled;
* when movement appears, the light turns on. If a thirty-second «off» timer was previously started, this timer is disabled;
* when motion is lost, a thirty second "off" timer is started. If he manages to reach the end, the light turns off.
* when motion is lost, a thirty second «off» timer is started. If he manages to reach the end, the light turns off.


<syntaxhighlight lang="ecmascript">
<syntaxhighlight lang="ecmascript">
Строка 65: Строка 66:
     then: function (newValue, devName, cellName) {
     then: function (newValue, devName, cellName) {
         if (newValue) {
         if (newValue) {
             dev["wb-gpio"]["Relay_1"] = true;
             dev["wb-gpio/Relay_1"] = true;
             if (motion_timer_1_id) {
             if (motion_timer_1_id) {
                 clearTimeout(motion_timer_1_id);
                 clearTimeout(motion_timer_1_id);
             }
             }
             motion_timer_1_id = setTimeout(function () {
             motion_timer_1_id = setTimeout(function () {
                 dev["wb-gpio"]["Relay_1"] = false;
                 dev["wb-gpio/Relay_1"] = false;
                 motion_timer_1_id = null;
                 motion_timer_1_id = null;
             }, motion_timer_1_timeout_ms);
             }, motion_timer_1_timeout_ms);
Строка 89: Строка 90:
       then: function(newValue, devName, cellName) {
       then: function(newValue, devName, cellName) {
           if (!newValue) {
           if (!newValue) {
               dev["wb-gpio"][relay_control] = true;
               dev["wb-gpio/relay_control"] = true;
               if (motion_timer_id) {
               if (motion_timer_id) {
                   clearTimeout(motion_timer_id);
                   clearTimeout(motion_timer_id);
Строка 95: Строка 96:


               motion_timer_id = setTimeout(function() {
               motion_timer_id = setTimeout(function() {
                   dev["wb-gpio"][relay_control] = false;
                   dev["wb-gpio/relay_control"] = false;
                   motion_timer_id = null;
                   motion_timer_id = null;
               }, timeout_ms);
               }, timeout_ms);
Строка 135: Строка 136:
     if ((date > date_start) && (date < date_end)) {
     if ((date > date_start) && (date < date_end)) {
       if (newValue) {
       if (newValue) {
           dev["wb-gpio"]["EXT1_R3A1"] = 1;
           dev["wb-gpio/EXT1_R3A1"] = 1;
    
    
           if (motion_timer_1_id) {
           if (motion_timer_1_id) {
Строка 142: Строка 143:
    
    
           motion_timer_1_id = setTimeout(function () {
           motion_timer_1_id = setTimeout(function () {
             dev["wb-gpio"]["EXT1_R3A1"] = 0;             
             dev["wb-gpio/EXT1_R3A1"] = 0;             
             motion_timer_1_id = null;
             motion_timer_1_id = null;
           }, motion_timer_1_timeout_ms);               
           }, motion_timer_1_timeout_ms);               
Строка 179: Строка 180:
   defineRule( "roller_shutter_up_on" + suffix, {
   defineRule( "roller_shutter_up_on" + suffix, {
   asSoonAs: function() {
   asSoonAs: function() {
     return dev[relay_up_device][relay_up_control];
     return dev["relay_up_device/relay_up_control"];
   },
   },
     then: function () {
     then: function () {
Строка 187: Строка 188:


       relay_up_timer_id = setTimeout(function() {
       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);
     }
     }
Строка 202: Строка 203:
        
        
       relay_down_timer_id = setTimeout(function() {
       relay_down_timer_id = setTimeout(function() {
         dev[relay_down_device][relay_down_control] = 0;
         dev["relay_down_device/relay_down_control"] = 0;
       }, timeout_s * 1000);
       }, timeout_s * 1000);
     }
     }
Строка 209: Строка 210:
   defineRule("roller_shutter_both_on" + suffix, {
   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"];
     },
     },
     then: function () {
     then: function () {
Строка 222: Строка 223:
        
        
       dev[relay_up_device][relay_up_control] = 0;
       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");
     }
     }
Строка 296: Строка 297:
     then: function(newValue, devName, cellName) {
     then: function(newValue, devName, cellName) {
       if(newValue){
       if(newValue){
       dev["water_meters"]["water_meter_1"] = ((parseInt(newValue) - counterCorrection) * inpulseValue) + meterCorrection; // We multiply the value of the counter by the number of liters / pulse and add the correction value.
       dev["water_meters/water_meter_1"] = ((parseInt(newValue) - counterCorrection) * inpulseValue) + meterCorrection; // We multiply the value of the counter by the number of liters / pulse and add the correction value.
       }
       }
     }
     }
Строка 309: Строка 310:
To process clicks, you need to track the state of the counter of the desired type of click on the controller and, when it changes, perform an action.
To process clicks, you need to track the state of the counter of the desired type of click on the controller and, when it changes, perform an action.


<div lang="ru" dir="ltr" class="mw-content-ltr">
Handling counters is conveniently done on [[wb-rules]], but you can use any automation tool like [[Node-RED]]. To speed up meter polling, configure [[RS-485:Configuration via Web Interface#poll-period |poll period]].
Обработку счётчиков удобно делать на [[wb-rules]], но вы можете использовать любой инструмент для автоматизации, например, [[Node-RED]]. Чтобы ускорить опрос счетчиков, настройте [[RS-485:Configuration via Web Interface#poll-period |период опроса]].
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
=== Examples ===
=== Примеры ===
{{YouTube
{{YouTube
|link=https://youtu.be/C60KB7TCeKg
|link=https://youtu.be/C60KB7TCeKg
|text= Пример работы правила
|text= Rule example
}}
}}
В примере мы используем модуль [[WB-MCM8 Modbus Count Inputs | WB-MCM8]] для управления первым каналом диммера [[WB-MDM3 230V Modbus Dimmer | WB-MDM3]]:
In the example, we are using the [[WB-MCM8 Modbus Count Inputs | WB-MCM8]] to control the first dimmer channel [[WB-MDM3 230V Modbus Dimmer | WB-MDM3]]:
# Короткое нажатие включает канал.
# Short press turns on the channel.
# Двойное — выключает канал.
# Double - turns off the channel.
# Длинное — увеличивает яркость.
# Long - increases brightness.
# Короткое, а затем длинное — уменьшает яркость.
# Short, then long - reduces brightness.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
Since changing the brightness requires a time-consuming action, we use a timer. We also control the state of the input with the button and stop the action when the button is released.
Так как изменение яркости требует растянутое во времени действие, то мы используем таймер. Также мы контролируем состояние входа с кнопкой и прекращаем действие при отпускании кнопки.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="js">
<syntaxhighlight lang="js">
/* ---------------------------- */
/* ---------------------------- */
/* 1. Single Press Counter: On action*/
/* 1. Single Press Counter: On action*/
/* ---------------------------- */
/* ---------------------------- */
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
defineRule({
defineRule({
   whenChanged: "wb-mcm8_20/Input 1 Single Press Counter",
   whenChanged: "wb-mcm8_20/Input 1 Single Press Counter",
Строка 344: Строка 336:
   }
   }
});
});
</div>




<div lang="ru" dir="ltr" class="mw-content-ltr">
/* ---------------------------- */
/* ---------------------------- */
/* 2. Double Press Counter: Off action*/
/* 2. Double Press Counter: Off action*/
/* ---------------------------- */
/* ---------------------------- */
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
defineRule({
defineRule({
   whenChanged: "wb-mcm8_20/Input 1 Double Press Counter",
   whenChanged: "wb-mcm8_20/Input 1 Double Press Counter",
Строка 360: Строка 348:
   }
   }
});
});
</div>




<div lang="ru" dir="ltr" class="mw-content-ltr">
/* --------------------------------------- */
/* --------------------------------------- */
/* 3. Long Press Counter: Increase brightness */
/* 3. Long Press Counter: Increase brightness */
/* --------------------------------------- */
/* --------------------------------------- */
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
defineRule({
defineRule({
   whenChanged: "wb-mcm8_20/Input 1 Long Press Counter",
   whenChanged: "wb-mcm8_20/Input 1 Long Press Counter",
Строка 377: Строка 361:
   }
   }
});
});
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
// A rule that will increase the brightness on a timer
// A rule that will increase the brightness on a timer
defineRule({
defineRule({
Строка 385: Строка 367:
   then: function () {
   then: function () {
     var i = dev["wb-mdm3_58/Channel 1"];
     var i = dev["wb-mdm3_58/Channel 1"];
</div>


     <div lang="ru" dir="ltr" class="mw-content-ltr">
     if (i < 100 && dev["wb-mcm8_20/Input 1"]) {
if (i < 100 && dev["wb-mcm8_20/Input 1"]) {
       i++
       i++
       dev["wb-mdm3_58/Channel 1"] = i
       dev["wb-mdm3_58/Channel 1"] = i
Строка 396: Строка 376:
   }
   }
});
});
</div>




<div lang="ru" dir="ltr" class="mw-content-ltr">
/* -------------------------------------------- */
/* -------------------------------------------- */
/* 4. Shortlong Press Counter: Decrease brightness */
/* 4. Shortlong Press Counter: Decrease brightness */
/* -------------------------------------------- */
/* -------------------------------------------- */
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
defineRule({
defineRule({
   whenChanged: "wb-mcm8_20/Input 1 Shortlong Press Counter",
   whenChanged: "wb-mcm8_20/Input 1 Shortlong Press Counter",
Строка 413: Строка 389:
   }
   }
});
});
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
// A rule that will decrease the brightness on a timer
// A rule that will decrease the brightness on a timer
defineRule({
defineRule({
Строка 421: Строка 395:
   then: function () {
   then: function () {
     var i = dev["wb-mdm3_58/Channel 1"];
     var i = dev["wb-mdm3_58/Channel 1"];
</div>


     <div lang="ru" dir="ltr" class="mw-content-ltr">
     if (i > 0 && dev["wb-mcm8_20/Input 1"]) {
if (i > 0 && dev["wb-mcm8_20/Input 1"]) {
       i--
       i--
       dev["wb-mdm3_58/Channel 1"] = i
       dev["wb-mdm3_58/Channel 1"] = i
Строка 432: Строка 404:
   }
   }
});
});
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
=== Generic module for wb-rules ===
=== Универсальный модуль для wb-rules ===
We wrote a module for wb-rules [https://github.com/wirenboard/wb-community/tree/main/wb-press-actions wb-press-actions] that makes it easy to handle clicks in your scripts.
Мы написали модуль для wb-rules [https://github.com/wirenboard/wb-community/tree/main/wb-press-actions wb-press-actions], который облегчает обработку нажатий в ваших скриптах.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
== Sensor MSW v.3 ==
== Датчик MSW v.3 ==
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
When connecting the WB-MSW v.3 sensor to the Wiren Board controller, it is possible to create interesting scenarios using data from the sensor. For example, turn on the light when moving, signal with LEDs when the CO2 or VOC value is exceeded, turn on the air conditioner if it is hot or the air humidifier if the air is too dry. Rules are created individually for tasks. Here we will give some examples to understand the principle of working with the sensor. More examples of writing rules can be found in the '''[[Движок правил wb-rules | Rules engine wb-rules]]''' documentation.
При подключении датчика WB-MSW v.3 к контроллеру Wiren Board есть возможность создавать интересные сценарии, используя данные с датчика. На пример Включать свет по движению, сигнализировать светодиодами о превышении значения СО2 или VOC, Включать Кондиционер, если жарко или увлажнитель воздуха, если воздух слишком сухой. Правила создаются индивидуально под задачи. Здесь мы приведем несколько примеров для понимания принципа работы с датчиком. Больше примеров написания правил можно найти в документации '''[[Движок правил wb-rules]]'''.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
=== CO2 ===
=== CO2 ===
При концентрации CO2 меньше 650 - раз в 10 секунд мигаем зеленым.
When the CO2 concentration is less than 650, we flash green once every 10 seconds.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
When the CO2 concentration is over 651, but less than 1000, we flash yellow once every 5 seconds.
При концентрации CO2 свыше 651, но меньше 1000 - раз в 5 секунд мигаем желтым.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
When the CO2 concentration is over 1001, we flash red once a second.
При концентрации CO2 свыше 1001 - раз в секунду мигаем красным.
<div class="mw-collapsible mw-collapsed"; style="width:600px; overflow: hidden;">
<div class="mw-collapsible mw-collapsed"; style="width:600px; overflow: hidden;">
<syntaxhighlight lang="ecmascript">
<syntaxhighlight lang="ecmascript">
Строка 470: Строка 428:
         var co2_middle = newValue < 1000 && newValue > 651;
         var co2_middle = newValue < 1000 && newValue > 651;
         var co2_bad = newValue > 1001;
         var co2_bad = newValue > 1001;
</div>


         <div lang="ru" dir="ltr" class="mw-content-ltr">
         if (co2_good) {
if (co2_good) {
             dev["devName/Green LED"] = true;
             dev[devName]["Green LED"] = true;
             dev["devName/Red LED"] = false;
             dev[devName]["Red LED"] = false;
             dev["devName/LED Period (s)"] = 10;
             dev[devName]["LED Period (s)"] = 10;
         }
         }
         if (co2_middle) {
         if (co2_middle) {
             dev[devName]["Green LED"] = true;
             dev["devName/Green LED"] = true;
             dev[devName]["Red LED"] = true;
             dev["devName/Red LED"] = true;
             dev[devName]["LED Period (s)"] = 5;
             dev["devName/LED Period (s)"] = 5;
         }
         }
         if (co2_bad) {
         if (co2_bad) {
             dev[devName]["Green LED"] = false;
             dev["devName/Green LED"] = false;
             dev[devName]["Red LED"] = true;
             dev["devName/Red LED"] = true;
             dev[devName]["LED Period (s)"] = 1;
             dev["devName/LED Period (s)"] = 1;
         }
         }
     }
     }
Строка 493: Строка 449:
</div>
</div>
=== Max Motion ===
=== Max Motion ===
"Max Motion" - максимальное значение датчика движения за N время. Время от 1 до 60 секунд можно выставить в 282 регистре. По умолчанию 10 секунд. При достижении Max Motion значения 50 проверяем достаточно ли освещена комната, если нет - включаем свет. Как только значение Max Motion упадет ниже 50 свет выключаем.
"Max Motion" - the maximum value of the motion sensor for N time. Time from 1 to 60 seconds can be set in register 282. The default is 10 seconds. When the Max Motion value reaches 50, we check whether the room is sufficiently lit, if not, turn on the light. As soon as the Max Motion value drops below 50, turn off the light.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<div class="NavFrame">
<div class="NavFrame">
   <div class="NavContent">
   <div class="NavContent">
Строка 504: Строка 458:
     then: function(newValue, devName, cellName) {
     then: function(newValue, devName, cellName) {
         if (newValue > 50) {
         if (newValue > 50) {
             if (dev["wb-msw-v3_97"]["Illuminance"] < 50) {
             if (dev["wb-msw-v3_97/Illuminance"] < 50) {
                 dev["wb-mr3_11"]["K1"] = true;
                 dev["wb-mr3_11/K1"] = true;
             }
             }
         } else {
         } else {
             dev["wb-mr3_11"]["K1"] = false;
             dev["wb-mr3_11/K1"] = false;
         }
         }
     }
     }
});
});
</syntaxhighlight>
</syntaxhighlight>
</div>
</div>
</div>
</div>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
=== System rules ===
== Системные правила ==
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
Many of the indications that are visible in the web interface of the controller out of the box are also created by rules on the wb-rules engine. Their code is here: [https://github.com/wirenboard/wb-rules-system https://github.com/wirenboard/wb-rules-system]. The system rules are collected in the <code>wb-rules-system</code> package, the script files on the controller are located in the <code>/usr/share/wb-rules-system/</code> folder.  
Многие показания, которые видны в веб-интерфейсе контроллера из коробки, тоже создаются правилами на движке wb-rules. Их код находится здесь: [https://github.com/wirenboard/wb-rules-system https://github.com/wirenboard/wb-rules-system]. Системные правила собраны в пакет <code>wb-rules-system</code>, сами файлы скриптов на контроллере находятся в папке <code>/usr/share/wb-rules-system/</code>.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
A few examples of system rules are below.
Несколько примеров системных правил ниже.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
=== Rule for tweeters ===
=== Правило для пищалки ===
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
[https://github.com/contactless/wb-rules-system/blob/master/rules/buzzer.js Rule] creates a virtual buzzer device with volume and frequency sliders and a mute button.
[https://github.com/contactless/wb-rules-system/blob/master/rules/buzzer.js Правило] создаёт виртуальное устройство buzzer с ползунками для регулировки громкости и частоты, а также кнопкой включения звука.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="ecmascript">
<syntaxhighlight lang="ecmascript">
defineVirtualDevice("buzzer", {
defineVirtualDevice("buzzer", {
   title: "Buzzer", //
   title: "Buzzer", //
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   cells: {
cells: {
     frequency : {
     frequency : {
         type : "range",
         type : "range",
Строка 561: Строка 501:
   }
   }
});
});
</div>




<div lang="ru" dir="ltr" class="mw-content-ltr">
// setup pwm2
// setup pwm2
runShellCommand("echo 2 > /sys/class/pwm/pwmchip0/export");
runShellCommand("echo 2 > /sys/class/pwm/pwmchip0/export");
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
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);
         var duty_cycle = parseInt(dev.buzzer.volume  * 1.0  / 100 * period * 0.5);
         var duty_cycle = parseInt(dev.buzzer.volume  * 1.0  / 100 * period * 0.5);
</div>




         <div lang="ru" dir="ltr" class="mw-content-ltr">
         runShellCommand("echo " + period + " > /sys/class/pwm/pwmchip0/pwm2/period");
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");
};
};
</div>




<div lang="ru" dir="ltr" class="mw-content-ltr">
defineRule("_system_buzzer_params", {
defineRule("_system_buzzer_params", {
   whenChanged: [
   whenChanged: [
Строка 589: Строка 521:
     "buzzer/volume",
     "buzzer/volume",
     ],
     ],
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   then: function (newValue, devName, cellName) {
then: function (newValue, devName, cellName) {
     if ( dev.buzzer.enabled) {
     if ( dev.buzzer.enabled) {
         _buzzer_set_params();
         _buzzer_set_params();
Строка 598: Строка 528:
   }
   }
});
});
</div>




<div lang="ru" dir="ltr" class="mw-content-ltr">
defineRule("_system_buzzer_onof", {
defineRule("_system_buzzer_onof", {
   whenChanged: "buzzer/enabled",
   whenChanged: "buzzer/enabled",
Строка 613: Строка 541:
   }
   }
});
});
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
=== Power status rule ===
=== Правило для статуса питания ===
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
[https://github.com/contactless/wb-rules-system/blob/master/rules/power_status.js Rule] creates a virtual device that reports the current power status. Two ADC channels are used as input data: battery voltage measurement and input voltage measurement.
[https://github.com/contactless/wb-rules-system/blob/master/rules/power_status.js Правило] создаёт виртуальное устройство, которое сообщает текущий статус питания. В качестве входных данных используется два канала АЦП: измерение напряжения на аккумуляторе и измерение входного напряжения.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
The following logic is implemented:
Реализована следующая логика:
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
1. If the input voltage is less than the battery voltage, then the board is powered by the battery. In this case, 0V is also displayed as the input voltage.
1. Если входное напряжение меньше напряжение на аккумуляторе, то значит плата питается от аккумулятора. В этом случае, также отображается 0V в качестве входного напряжения.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
2. If the input voltage is greater than the battery voltage, then the board is powered by an external power source. The measurement from the Vin channel is displayed as the input voltage.
2. Если входное напряжение  больше напряжения на аккумуляторе, то плата работает от внешнего источника питания. В качестве входонго напряжения отображается измерение с канала Vin.
</div>




<div lang="ru" dir="ltr" class="mw-content-ltr">
To illustrate, the rules use two different ways of triggering: by changing the value of the control (rule _system_track_vin) and by changing the value of the expression (the other two).
Для иллюстрации правила используют два разных способа срабатывания: по изменению значения контрола (правило _system_track_vin) и по изменению значения выражения (два других).
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="ecmascript">
<syntaxhighlight lang="ecmascript">
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
defineVirtualDevice("power_status", {
defineVirtualDevice("power_status", {
   title: "Power status", //
   title: "Power status", //
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   cells: {
cells: {
     'working on battery' : {
     'working on battery' : {
         type : "switch",
         type : "switch",
Строка 664: Строка 572:
         value : 0
         value : 0
     }
     }
</div>




   <div lang="ru" dir="ltr" class="mw-content-ltr">
   }
}
});
});
</div>






<div lang="ru" dir="ltr" class="mw-content-ltr">
defineRule("_system_track_vin", {
defineRule("_system_track_vin", {
     whenChanged: "wb-adc/Vin",
     whenChanged: "wb-adc/Vin",
     then: function() {
     then: function() {
         if (dev["wb-adc"]["Vin"] < dev["wb-adc"]["BAT"] ) {
         if (dev["wb-adc/Vin"] < dev["wb-adc/BAT"] ) {
             dev["power_status"]["Vin"] = 0;
             dev["power_status/Vin"] = 0;
         } else {
         } else {
             dev["power_status"]["Vin"] = dev["wb-adc"]["Vin"] ;
             dev["power_status/Vin"] = dev["wb-adc/Vin"] ;
         }
         }
     }
     }
});
});
</div>






<div lang="ru" dir="ltr" class="mw-content-ltr">
defineRule("_system_dc_on", {
defineRule("_system_dc_on", {
   asSoonAs: function () {
   asSoonAs: function () {
     return  dev["wb-adc"]["Vin"] > dev["wb-adc"]["BAT"];
     return  dev["wb-adc/Vin"] > dev["wb-adc/BAT"];
   },
   },
   then: function () {
   then: function () {
     dev["power_status"]["working on battery"] = false;
     dev["power_status/working on battery"] = false;
   }
   }
});
});
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
defineRule("_system_dc_off", {
defineRule("_system_dc_off", {
   asSoonAs: function () {
   asSoonAs: function () {
     return  dev["wb-adc"]["Vin"] <= dev["wb-adc"]["BAT"];
     return  dev["wb-adc/Vin"] <= dev["wb-adc/BAT"];
   },
   },
   then: function () {
   then: function () {
     dev["power_status"]["working on battery"] = true;
     dev["power_status/working on battery"] = true;
   }
   }
});
});
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
== Thermostat ==
== Термостат ==
An example of a simple thermostat from the [https://support.wirenboard.com/t/novaya-versiya-dvizhka-pravil/4196/158 topic on the support portal].
Пример простого термостата из [https://support.wirenboard.com/t/novaya-versiya-dvizhka-pravil/4196/158 темы на портале поддержки].
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="js">
<syntaxhighlight lang="js">
defineVirtualDevice("Termostat", {
defineVirtualDevice("Termostat", {
     title: "Termostat",
     title: "Termostat",
     cells: {
     cells: {
       // =============== Прихожая теплый пол
       // =============== hallway underfloor heating
       "R01-TS16-1-mode": {//режим 0-ручной 1-по расписанию
       "R01-TS16-1-mode": {//mode 0-manual 1-scheduled
    type: "switch",
    type: "switch",
    value: false,
    value: false,
    },
    },
       "R01-TS16-1-setpoint": {//уставка
       "R01-TS16-1-setpoint": {//setting
    type: "range",
    type: "range",
    value: 25,
    value: 25,
Строка 736: Строка 630:
         readonly: false
         readonly: false
    },
    },
       "R01-TS16-1-lock": {//блокировка в визуализации 0-снята 1-заблокирована
       "R01-TS16-1-lock": {//blockage in visualization 0-unlocked 1-blocked
    type: "switch",
    type: "switch",
    value: false,
    value: false,
    },.......
    },.......
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
var hysteresis = 0.5;
var hysteresis = 0.5;
function Termostat(name, temp, setpoint, TS, TS_onoff) {
function Termostat(name, temp, setpoint, TS, TS_onoff) {
defineRule(name, {  
defineRule(name, {
   whenChanged: temp, //при изменении состояния датчика
   whenChanged: temp, //when the sensor state changes
   then: function (newValue, devName, cellName) { //выполняй следующие действия
   then: function (newValue, devName, cellName) { // do the following
     if (dev[TS_onoff]) {
     if (dev[TS_onoff]) {
    if ( newValue < dev[setpoint] - hysteresis) { //если температура датчика меньше уставки - гистерезис
    if ( newValue < dev[setpoint] - hysteresis) { //if the sensor temperature is less than the setpoint - hysteresis
      dev[TS] = true;
      dev[TS] = true;
    }
    }
    if ( newValue > dev[setpoint] + hysteresis) { //если температура датчика больше виртуальной уставки + гистерезис
    if ( newValue > dev[setpoint] + hysteresis) { //if the sensor temperature is greater than the virtual setpoint + hysteresis
      dev[TS] = false;
      dev[TS] = false;
    }
    }
     }
     }
     else dev[TS] = false;
     else dev[TS] = false;
Строка 760: Строка 652:
});
});
}
}
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
Termostat("R01-TS16-1", "A60-M1W3/External Sensor 1", "Termostat/R01-TS16-1-setpoint", "wb-gpio/EXT4_R3A1", "Termostat/R01-TS16-1-onoff"); //  
Termostat("R01-TS16-1", "A60-M1W3/External Sensor 1", "Termostat/R01-TS16-1-setpoint", "wb-gpio/EXT4_R3A1", "Termostat/R01-TS16-1-onoff"); // Прихожая теплый пол
Hallway underfloor heating
</div>






<div lang="ru" dir="ltr" class="mw-content-ltr">
</syntaxhighlight>
</syntaxhighlight>
== Отправка команд по RS-485 ==
== Sending commands via RS-485 ==
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
For example, send a command to the device on the port /dev/ttys0 (corresponds to the hardware port RS-485-ISO on the [[Special:MyLanguage/Wiren Board 4|Wiren Board 4]]). To do this, we will use the rules engine and the ability to execute arbitrary shell commands. See [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 documentation] for details.
Для примера отправим команду устройству на порт ''/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 в документации].
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
Create a virtual device with switch type control via rules engine.  
С помощью движка правил создадим виртуальное устройство с контролом типа switch (переключатель).
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
When you turn on the switch a command will be sent: (Set Brightness ch. 00=0xff) for Uniel UCH-M141:
При включении переключателя будем отправлять команду (уст. Яркость кан. 00=0xff) для Uniel UCH-M141:
<pre>
<pre>
FF FF 0A 01 FF 00 00 0A
FF FF 0A 01 FF 00 00 0A
</pre>
</pre>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
When you turn off the switch  a command will be sent: (set channel brightness 00=0x00) for Uniel UCH-M141:
При выключении переключателя будем отправлять команду (уст. Яркость кан. 00=0x00) для Uniel UCH-M141:
<pre>
<pre>
FF FF 0A 01 00 00 00 0B
FF FF 0A 01 00 00 00 0B
</pre>
</pre>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
1. Port setting
1. Настройка порта
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
To configure the / dev/ttyNSC0 port to 9600 speed, run the following command
Для настройки порта /dev/ttyNSC0 на скорость 9600 надо выполнить следующую команду
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<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>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
2. Sending a command
2. Отправка команды
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
Sending data is done with the following shell command:
Отправка данных делается следующей шелл-командой:
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<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
</pre>
</pre>
где "\xFF\xFF\x0A\x01\xD1\x06\x00\xE2" - это запись команды "FF FF 0A 01 D1 06 00 E2".
where "\xFF\xFF\x0A\x01\xD1\x06\x00\xE2" - is the entry of a "FF FF 0A 01 D1 06 00 E2" command.
</div>




<div lang="ru" dir="ltr" class="mw-content-ltr">
3. Create the new rules file <code>/etc/wb-rules/rs485_cmd.js</code> in the rules engine
3. Создадим в движке правил новый файл с правилами <code>/etc/wb-rules/rs485_cmd.js</code>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
The file can be edited with vim, nano, or mcedit in an ssh session on the device, or it can be downloaded with SCP.
Файл можно редактировать с помощью vim, nano или mcedit в сеансе ssh на устройстве, либо залить его с помощью SCP.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<pre>
<pre>
root@wirenboard:~# mcedit  /etc/wb-rules/rs485_cmd.js
root@wirenboard:~# mcedit  /etc/wb-rules/rs485_cmd.js
</pre>
</pre>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
4. Describe the virtual device in the file
4. Описываем в файле виртуальный девайс
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="ecmascript">
<syntaxhighlight lang="ecmascript">
defineVirtualDevice("rs485_cmd", {
defineVirtualDevice("rs485_cmd", {
Строка 856: Строка 714:
});
});
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
5. Restart wb-rules and check the operation
5. Перезапускаем wb-rules и проверяем работу
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<pre>
<pre>
root@wirenboard:~# /etc/init.d/wb-rules restart
root@wirenboard:~# /etc/init.d/wb-rules restart
root@wirenboard:~# tail -f /var/log/messages
root@wirenboard:~# tail -f /var/log/messages
</pre>
</pre>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
There should be no error messages in the log (exit via control-c)
В логе не должно быть сообщений об ошибке (выход через control-c)
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
A new device "Send custom command to RS-485 port" should appear in the Devices section of the web interface.
В веб-интерфейсе в разделе Devices должно появиться новое устройство "Send custom command to RS-485 port".
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
6. Add a function to configure the port.
6. Добавим функцию для конфигурирования порта.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="ecmascript">
<syntaxhighlight lang="ecmascript">
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");
}
}
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
7. Let's describe the rules for turning the switch on and off
7. Опишем правила на включение и выключение переключателя
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="ecmascript">
<syntaxhighlight lang="ecmascript">
defineRule("_rs485_switch_on", {
defineRule("_rs485_switch_on", {
Строка 906: Строка 746:
   }
   }
});
});
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
defineRule("_rs485_switch_off", {
defineRule("_rs485_switch_off", {
   asSoonAs: function () {
   asSoonAs: function () {
Строка 917: Строка 755:
   }
   }
});
});
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
Note the double shielding.
Обратите внимание на двойное экранирование.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
7. Putting it all together
7. Собираем всё вместе
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
The full contents of the file with the rules:
Полное содержимое файла с правилами:
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="ecmascript">
<syntaxhighlight lang="ecmascript">
defineVirtualDevice("rs485_cmd", {
defineVirtualDevice("rs485_cmd", {
Строка 946: Строка 774:
     }
     }
});
});
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
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");
}
}
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
defineRule("_rs485_switch_on", {
defineRule("_rs485_switch_on", {
   asSoonAs: function () {
   asSoonAs: function () {
Строка 963: Строка 787:
   }
   }
});
});
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
defineRule("_rs485_switch_off", {
defineRule("_rs485_switch_off", {
   asSoonAs: function () {
   asSoonAs: function () {
Строка 974: Строка 796:
   }
   }
});
});
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
setTimeout(setup_port, 1000); // set setup_port() running 1 second after starting.
setTimeout(setup_port, 1000); // запланировать выполнение setup_port() через 1 секунду после старта правил.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
== Sending a message via Telegram bot ==
== Отправка сообщения через Telegram-бота ==
{{Anchor|telegram}}
{{Anchor|telegram}}
Сообщения отправляются с использованием [https://core.telegram.org/api#telegram-api Telegram API] через <code>curl</code>.
Messages are sent using [https://core.telegram.org/api#telegram-api Telegram API] via <code>curl</code>.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="ecmascript">
<syntaxhighlight lang="ecmascript">
var message = "Text"; // напишите свой текст сообщения
varmessage = "Text"; // write your message text
var token = "TOKEN"; // замените на токен бота
var token = "TOKEN"; // replace with bot token
var chat_id = CHATID; // замените на свой chat_id
var chat_id = CHATID; // replace with your chat_id
var command = 'curl -s -X POST https://api.telegram.org/bot{}/sendMessage -d chat_id={} -d text="{}"'.format(token, chat_id, message);
var command = 'curl -s -X POST https://api.telegram.org/bot{}/sendMessage -d chat_id={} -d text="{}"'.format(token, chat_id, message);
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
runShellCommand(command);
runShellCommand(command);
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
== Handling errors when working with serial devices ==
== Обработка ошибок в работе с serial-устройствами ==
Implemented by subscribing to all '''meta/error''' topics.
Реализована через подписку на все топики '''meta/error'''.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="ecmascript">
<syntaxhighlight lang="ecmascript">
defineVirtualDevice("meta_error_test", {
defineVirtualDevice("meta_error_test", {
Строка 1025: Строка 833:
   }
   }
});
});
</div>


   
   
<div lang="ru" dir="ltr" class="mw-content-ltr">
trackMqtt("/devices/+/controls/+/meta/error", function(message){
trackMqtt("/devices/+/controls/+/meta/error", function(message){
   log.info("name: {}, value: {}".format(message.topic, message.value))
   log.info("name: {}, value: {}".format(message.topic, message.value))
Строка 1038: Строка 844:
});
});
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
== Custom fields in web interface ==
== Пользовательские поля в веб-интерфейсе ==
</div>




<div lang="ru" dir="ltr" class="mw-content-ltr">
[[File:Sample-custom-config-1.png|300px|thumb|right|Example configuration]]
[[File:Sample-custom-config-1.png|300px|thumb|right|Пример конфигурации]]
[[File:Sample-custom-config-2.png|300px|thumb|right|Example script]]
[[File:Sample-custom-config-2.png|300px|thumb|right|Пример скрипта]]
If you need to manually enter temperature and humidity settings in the interface of the Wiren Board controller.  
Задача - надо в веб-интерфейсе контроллера Wiren Board вводить уставки  температуры и влажности.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
An easy way is to do in the defineVirtualDevice() field, make it readonly: false. And it will appear in the web interface in Devices as editable, and the value will be saved in the rules engine.
Простой способ, это сделать в defineVirtualDevice() поле, ему сделать readonly: false. И оно появится в веб-интерфейсе в Devices как редактируемое, а значение будет сохраняться в движке правил.
But a complex setup with menus and options cannot be done this way.
Но сложную настройку с меню и вариантами так не сделать.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
The correct but tricky way is to create a new tab in the Configs section with editable settings options fields.
Правильный, но сложный способ — создать новую вкладку в разделе Configs с редактируемыми полями параметров установок .
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
Three files are required:
Потребуются три файла:
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
1. The output scheme of the html page in the Configs  
1. Схема вывода html странички в разделе Configs : /usr/share/wb-mqtt-confed/schemas/test-config.schema.json
section: /usr/share/wb-mqtt-confed/schemas/test-config.schema.json
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
{
{
Строка 1071: Строка 866:
"title":"Test configuration",
"title":"Test configuration",
"description":"Long description configuration",
"description":"Long description configuration",
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
"configFile": {
"configFile": {
"path":"/etc/test-config.conf",
"path":"/etc/test-config.conf",
"service":"wb-rules"
"service":"wb-rules"
},
},
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
"properties": {
"properties": {
"temperature_setpoint": {
"temperature_setpoint": {
Строка 1090: Строка 881:
"maximum": 40
"maximum": 40
},
},
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
"humidity_setpoint": {
"humidity_setpoint": {
"type":"number",
"type":"number",
Строка 1105: Строка 894:
}
}
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
2. Description of the default configuration (when saving the form in the web interface, the values will be written to this file) : /etc/test-config.conf
2. Описание конфигурации по умолчанию (при сохранении формы в веб интерфейсе, значения запишутся в этот файл) : /etc/test-config.conf
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
{
{
Строка 1115: Строка 902:
}
}
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
3. Script that updates config  : /mnt/data/etc/wb-rules/test-config-script.js
3. Скрипт, обновляющий конфиг : /mnt/data/etc/wb-rules/test-config-script.js
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
var config = readConfig("/etc/test-config.conf");
var config = readConfig("/etc/test-config.conf");
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
log("temperature setpoint is: {}".format(config.temperature_setpoint));
log("temperature setpoint is: {}".format(config.temperature_setpoint));
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
The last file can also be edited from the web interface on the Scripts tab.
Последний файл можно в том числе редактировать из веб-интерфейса на вкладке Scripts.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
In the json file describes the schema of the output html page browser, according to generally accepted mapping standard. Description of keys here: json-schema.org ahhh!
В json файлах описаны схемы вывода html странички браузером, по общепринятому стандарту отображения. Описание ключей тут: json-schema.org.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
After creating the files, you need to restart the services
После создания файлов, нужно выполнить рестарт сервисов
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
service wb-mqtt-confed restart
service wb-mqtt-confed restart
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
service wb-rules restart
service wb-rules restart
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
When you click Save in the web interface, the wb-rules service will be restarted, and the values of the settings will be written to the rules.
При нажатии кнопки Save в веб-интерфейсе, будет перезапускаться сервис wb-rules, а значения установок - записываться в правила.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
== Complex rules with schedules ==
== Сложные правила с расписаниями ==
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
The object is a grocery store. Various store systems are controlled by feedback from temperature sensors and taking into account the store's work schedule.
Объект - продуктовый магазин. Различные системы магазина управляются по обратной связи от датчиков температуры и с учётом расписания работы магазина.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
Not cron-rules are used for schedules, but  the libschedule. The libschedule enables and disables rules, which, unlike cron rules, are executed continuously when enabled.
Для расписаний используются не cron-правила, а обёртка над ними. Обёртка включает и выключает правила, которые, в отличие от cron-правил, выполняются постоянно, будучи включенными.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
For example, we want the lighting to be on from 10 to 17h. The libschedule will follow the «turn on the lights» rule once a minute from 10 am to 17 PM.
Например, мы хотим, чтобы освещение было включено с 10 до 17ч. Обёртка (libschedule) будет выполнять правило "включить освещение" раз в минуту с 10 утра до 17 вечера.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
This means that even if the controller is running intermittently and missed the transition time between schedules (10 am), the controller will still turn on the lights at the first opportunity.
Это значит, что даже если контроллер работает с перерывами и пропустил время перехода между расписаниями (10 утра), то контроллер всё равно включит освещение при первой возможности.
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
lib_schedules.js:
lib_schedules.js:
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="ecmascript">
<syntaxhighlight lang="ecmascript">
global.__proto__.Schedules = {};
global.__proto__.Schedules = {};
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
(function(Schedules) { // closing
(function(Schedules) { // замыкание
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   function todayAt(now, hours, minutes) {
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!
Строка 1198: Строка 949:
     return date;
     return date;
   }
   }
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   function checkScheduleInterval(now, start_time, end_time) {
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));
</div>


     <div lang="ru" dir="ltr" class="mw-content-ltr">
     if (end_date >= start_date) {
if (end_date >= start_date) {
       if ((now >= start_date) && (now < end_date)) {
       if ((now >= start_date) && (now < end_date)) {
         return true;
         return true;
Строка 1215: Строка 962:
       // end date is less than start date,  
       // end date is less than start date,  
       // assuming they belong to a different days (e.g. today and tomorrow)
       // assuming they belong to a different days (e.g. today and tomorrow)
</div>


       <div lang="ru" dir="ltr" class="mw-content-ltr">
       // option 1: what if it's now the day of "end" date?
// 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) {
         return true;
         return true;
       }
       }
</div>


       <div lang="ru" dir="ltr" class="mw-content-ltr">
       // well, that seems not to be the case. ok,
// 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:
</div>


       <div lang="ru" dir="ltr" class="mw-content-ltr">
       if (now >= start_date) {
if (now >= start_date) {
         return true;
         return true;
       }
       }
     }
     }
     return false;
     return false;
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   }
}
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   function checkSchedule(schedule, now) {
function checkSchedule(schedule, now) {
     if (now == undefined) {
     if (now == undefined) {
       now = new Date();
       now = new Date();
     }
     }
</div>


     <div lang="ru" dir="ltr" class="mw-content-ltr">
     for (var i = 0; i < schedule.intervals.length; ++i) {
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])) {
Строка 1264: Строка 999:
     dev["_schedules"][schedule.name] = checkSchedule(schedule);
     dev["_schedules"][schedule.name] = checkSchedule(schedule);
   };
   };
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   function addScheduleDevCronTasks(schedule) {
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];
Строка 1284: Строка 1017:
     }     
     }     
   }
   }
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   function addScheduleAutoUpdCronTask(schedule) {
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),
Строка 1295: Строка 1026:
     });
     });
   }
   }
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   var _schedules = {};
var _schedules = {};
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   Schedules.registerSchedule = function(schedule) {
Schedules.registerSchedule = function(schedule) {
     _schedules[schedule.name] = schedule;
     _schedules[schedule.name] = schedule;
   };
   };
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   Schedules.initSchedules = function() {
Schedules.initSchedules = function() {
     var params = {
     var params = {
       title: "Schedule Status",  
       title: "Schedule Status",  
       cells: {}
       cells: {}
     };
     };
</div>


     <div lang="ru" dir="ltr" class="mw-content-ltr">
     for (var schedule_name in _schedules) {
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];
Строка 1322: Строка 1045:
       }
       }
     };
     };
</div>


     <div lang="ru" dir="ltr" class="mw-content-ltr">
     defineVirtualDevice("_schedules", params);
defineVirtualDevice("_schedules", params);
</div>




     <div lang="ru" dir="ltr" class="mw-content-ltr">
     for (var schedule_name in _schedules) {
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];
</div>


         <div lang="ru" dir="ltr" class="mw-content-ltr">
         // setup cron tasks which updates the schedule dev status at schedule
// setup cron tasks which updates the schedule dev status at schedule
         //  interval beginings and ends
         //  interval beginings and ends
         addScheduleDevCronTasks(schedule);
         addScheduleDevCronTasks(schedule);
</div>


         <div lang="ru" dir="ltr" class="mw-content-ltr">
         // if needed, setup periodic task to trigger rules which use this schedule
// if needed, setup periodic task to trigger rules which use this schedule
         if (schedule.autoUpdate) {
         if (schedule.autoUpdate) {
           addScheduleAutoUpdCronTask(schedule);
           addScheduleAutoUpdCronTask(schedule);
         }
         }
</div>


         <div lang="ru" dir="ltr" class="mw-content-ltr">
         // set schedule dev status as soon as possible at startup
// set schedule dev status as soon as possible at startup
         (function(schedule) {
         (function(schedule) {
           setTimeout(function() {
           setTimeout(function() {
Строка 1355: Строка 1068:
           }, 1);
           }, 1);
         })(schedule);
         })(schedule);
</div>


       <div lang="ru" dir="ltr" class="mw-content-ltr">
       };
};
     };
     };
};
};
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
})(Schedules);
})(Schedules);
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="ru" dir="ltr" class="mw-content-ltr">
An example of a rule using Schedules:
Пример правил, с использованием Schedules:
<syntaxhighlight lang="ecmascript">
<syntaxhighlight lang="ecmascript">
(function() { // замыкание
(function() { // closing
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   defineAlias("countersTemperature", "wb-msw2_30/Temperature");
defineAlias("countersTemperature", "wb-msw2_30/Temperature");
   defineAlias("vegetablesTemperature", "wb-msw2_31/Temperature");
   defineAlias("vegetablesTemperature", "wb-msw2_31/Temperature");
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   defineAlias("heater1EnableInverted", "wb-mrm2-old_70/Relay 1");
defineAlias("heater1EnableInverted", "wb-mrm2-old_70/Relay 1");
   defineAlias("frontshopVentInverted", "wb-gpio/EXT1_R3A3");
   defineAlias("frontshopVentInverted", "wb-gpio/EXT1_R3A3");
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   Schedules.registerSchedule({
Schedules.registerSchedule({
     "name" : "signboard", // signboard
     "name" : "signboard", // вывеска
     "autoUpdate" : "1m",
     "autoUpdate" : "1m",
     "intervals" : [
     "intervals" : [
       [ [12, 30], [20, 30] ],  // в UTC, 15:30 - 23:30 MSK
       [ [12, 30], [20, 30] ],  // in UTC, 15:30 - 23:30 MSK
       [ [3, 30], [5, 20] ],  // в UTC, 6:30 - 8:20 MSK
       [ [3, 30], [5, 20] ],  // in UTC, 6:30 - 8:20 MSK
     ]
     ]
   });
   });
Строка 1397: Строка 1098:
     "autoUpdate" : "1m",
     "autoUpdate" : "1m",
     "intervals" : [
     "intervals" : [
       [ [4, 45], [20, 15] ],  // всё ещё UTC, 7:45 - 23:15 MSK
       [ [4, 45], [20, 15] ],  // still UTC, 07:45 - 23:15 MSK
     ]
     ]
   });
   });
Строка 1404: Строка 1105:
     "autoUpdate" : "1m",
     "autoUpdate" : "1m",
     "intervals" : [
     "intervals" : [
       [ [5, 0], [19, 0] ],  // всё ещё UTC, 8:00 - 22:00 MSK
       [ [5, 0], [19, 0] ],  // still UTC, 8:00 - 22:00 MSK
     ]
     ]
   });
   });
Строка 1411: Строка 1112:
     "autoUpdate" : "1m",
     "autoUpdate" : "1m",
     "intervals" : [
     "intervals" : [
       [ [4, 45], [19, 15] ],  // всё ещё UTC, 7:45 - 22:15 MSK
       [ [4, 45], [19, 15] ],  // still UTC, 7:45 - 22:15 MSK
     ]
     ]
   });
   });
Строка 1418: Строка 1119:
     "autoUpdate" : "1m",
     "autoUpdate" : "1m",
     "intervals" : [
     "intervals" : [
       [ [4, 20], [20, 45] ],  // всё ещё UTC, 7:20 -23:45 MSK
       [ [4, 20], [20, 45] ],  // still UTC, 7:20 -23:45 MSK
     ]
     ]
   });
   });
Строка 1424: Строка 1125:
     "name" : "heaters_schedule",
     "name" : "heaters_schedule",
     "intervals" : [
     "intervals" : [
       [ [4, 0], [17, 0] ],  // всё ещё UTC, 07:00 - 20:00 MSK дневной режим
       [ [4, 0], [17, 0] ],  // still UTC, 07:00 - 20:00 MSK дневной режим
     ]
     ]
   });
   });
   Schedules.initSchedules();
   Schedules.initSchedules();
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   // signboard and facade illumination
// Вывеска и фасадное освещение
   defineRule("signboardOnOff", {
   defineRule("signboardOnOff", {
     when: function() {
     when: function() {
Строка 1445: Строка 1144:
     }
     }
   });
   });
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   // sales area illumination
// Освещение торгового зала
   defineRule("lightingFrontshopOnOff", {
   defineRule("lightingFrontshopOnOff", {
     when: function() {
     when: function() {
Строка 1455: Строка 1152:
     then: function (newValue, devName, cellName) {
     then: function (newValue, devName, cellName) {
       log("lightingFrontshopOnOff  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       log("lightingFrontshopOnOff  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       dev["wb-gpio/EXT1_R3A1"] = ! dev._schedules.frontshop_lighting; //инвертированный контактор
       dev["wb-gpio/EXT1_R3A1"] = ! dev._schedules.frontshop_lighting; //inverted contactor
     }
     }
   });
   });
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   // backstoreroom ventilation
// Вентиляция подсобного помещения
   defineRule("ventBackstoreOnOff", {
   defineRule("ventBackstoreOnOff", {
     when: function() {
     when: function() {
Строка 1469: Строка 1164:
       log("ventBackstoreOnOff  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       log("ventBackstoreOnOff  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       var on = dev._schedules.ext_working_hours_15m;
       var on = dev._schedules.ext_working_hours_15m;
       dev["wb-mr6c_81/K1"] = ! on; //инвертированный контактор
       dev["wb-mr6c_81/K1"] = ! on; //inverted contactor
       dev["wb-mr6c_81/K5"] = ! on; //инвертированный контактор
       dev["wb-mr6c_81/K5"] = ! on; //inverted contactor
     }
     }
   });
   });
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   // Freezer showcase illumination
// Освещение холодильных горок
   defineRule("lightingCoolingshelfsOnOff", {
   defineRule("lightingCoolingshelfsOnOff", {
     when: function() {
     when: function() {
Строка 1484: Строка 1177:
       log("lightingCoolingshelfsOnOff  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       log("lightingCoolingshelfsOnOff  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       var on = dev._schedules.working_hours_15m;
       var on = dev._schedules.working_hours_15m;
</div>


       <div lang="ru" dir="ltr" class="mw-content-ltr">
       //  
// освещение в горках через нормально-закрытые реле (инвертировано)
the lighting in the freezer showcases via the normally-closed relays (inverted)
       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;
Строка 1498: Строка 1190:
     }
     }
   });
   });
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   //Display fridges
//Брендовые холодильники (пиво, лимонады)
   defineRule("powerBrandFridgesOnOff", {
   defineRule("powerBrandFridgesOnOff", {
     when: function() {
     when: function() {
Строка 1510: Строка 1200:
       var on = dev._schedules.working_hours;
       var on = dev._schedules.working_hours;
        
        
       dev["wb-gpio/EXT1_R3A5"] = !on; // инвертировано
       dev["wb-gpio/EXT1_R3A5"] = !on; // inverted
     }
     }
   });
   });
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   // ========= Boilers and supply ventilation ТЗ ===========
// ========= Котлы и приточная вентиляция ТЗ ===========
   // feedback on the temperature of the vegetable zone
   // обратная связь по температуре овощной зоны
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   // position controller works daily
// днём работает позиционный регулятор
   defineRule("heatersDayOff", {
   defineRule("heatersDayOff", {
     when: function() {
     when: function() {
Строка 1528: Строка 1214:
     then: function (newValue, devName, cellName) {
     then: function (newValue, devName, cellName) {
       log("heatersDayOff  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       log("heatersDayOff  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       heater1EnableInverted = !false; // инвертировано
       heater1EnableInverted = !false; // inverted
     }
     }
   });
   });
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   defineRule("heatersDayOn", {
defineRule("heatersDayOn", {
     when: function() {
     when: function() {
       return (dev._schedules.heaters_schedule) && (vegetablesTemperature < 16.7);
       return (dev._schedules.heaters_schedule) && (vegetablesTemperature < 16.7);
Строка 1540: Строка 1224:
     then: function (newValue, devName, cellName) {
     then: function (newValue, devName, cellName) {
       log("heatersDayOn  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       log("heatersDayOn  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       heater1EnableInverted = !true; // инвертировано
       heater1EnableInverted = !true; // inverted
     }
     }
   });
   });
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   // position controller works at night
// ночью работает позиционный регулятор
   defineRule("heatersNightOff", {
   defineRule("heatersNightOff", {
     when: function() {
     when: function() {
Строка 1553: Строка 1235:
     then: function (newValue, devName, cellName) {
     then: function (newValue, devName, cellName) {
       log("heatersNightOff  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       log("heatersNightOff  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       heater1EnableInverted = !false; // инвертировано
       heater1EnableInverted = !false; // inverted
     }
     }
   });
   });
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   defineRule("heatersNightOn", {
defineRule("heatersNightOn", {
     when: function() {
     when: function() {
       return (!dev._schedules.heaters_schedule) && (vegetablesTemperature < 11.3);
       return (!dev._schedules.heaters_schedule) && (vegetablesTemperature < 11.3);
Строка 1565: Строка 1245:
     then: function (newValue, devName, cellName) {
     then: function (newValue, devName, cellName) {
       log("heatersNightOn  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       log("heatersNightOn  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       heater1EnableInverted = !true; // инвертировано
       heater1EnableInverted = !true; // inverted
     }
     }
   });
   });
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   // supply and exhaust ventilation are forcibly switched off
// приточная и вытяжная вентиляция принудительно выключены
    
    
   defineRule("ventFrontshopAlwaysOff", {
   defineRule("ventFrontshopAlwaysOff", {
Строка 1581: Строка 1259:
   });
   });
    
    
   // ==================  Кассовая зона =================
 
</div>
   // ==================  The cash register area =================


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   // in the checkout area during working hours, the temperature is maintained by air conditioners (position controller)
// в кассовой зоне в рабочее время температура поддерживается кондиционерами (позиционный регулятор)
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   defineRule("countersACOn", {
defineRule("countersACOn", {
     when: function() {
     when: function() {
       return (dev._schedules.working_hours_15m) && (countersTemperature < 17.7);
       return (dev._schedules.working_hours_15m) && (countersTemperature < 17.7);
Строка 1595: Строка 1270:
     then: function (newValue, devName, cellName) {
     then: function (newValue, devName, cellName) {
       log("countersACOn  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       log("countersACOn  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       dev["wb-mir_75/Play from ROM7"] = true; // кондиционер кассовой зоны на нагрев
       dev["wb-mir_75/Play from ROM7"] = true; // air conditioning cash area for heating
     }
     }
   });
   });
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   // after working hours, the air conditioning is off
// в нерабочее время кондиционер выключен
   defineRule("countersACOff", {
   defineRule("countersACOff", {
     when: function() {
     when: function() {
Строка 1608: Строка 1281:
     then: function (newValue, devName, cellName) {
     then: function (newValue, devName, cellName) {
       log("countersACOff  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       log("countersACOff  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       dev["wb-mir_75/Play from ROM2"] = true; // кондиционер кассовой зоны выключить
       dev["wb-mir_75/Play from ROM2"] = true; // shut down air conditioning cash area
     }
     }
   });
   });
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   // =============== Vegetable Zone ==============
// =============== Овощная зона ==============
   // Refrigeration of vegetables with air conditioning only when the air temperature is above 18.5C   
   // Охлаждение овощей кондиционером только при температуре воздуха выше 18.5C
</div>  


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   defineRule("acVegOn", {
defineRule("acVegOn", {
     when: function() {
     when: function() {
       return vegetablesTemperature >= 18.5
       return vegetablesTemperature >= 18.5
Строка 1625: Строка 1294:
     then: function (newValue, devName, cellName) {
     then: function (newValue, devName, cellName) {
       log("acVegOn  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       log("acVegOn  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       dev["wb-mir_76/Play from ROM3"] = true; // Охлаждение +18
       dev["wb-mir_76/Play from ROM3"] = true; // Cooling +18
     }
     }
   });
   });
</div>


   <div lang="ru" dir="ltr" class="mw-content-ltr">
   defineRule("acVegOff", {
defineRule("acVegOff", {
     when: function() {
     when: function() {
       return vegetablesTemperature < 17.8
       return vegetablesTemperature < 17.8
Строка 1637: Строка 1304:
     then: function (newValue, devName, cellName) {
     then: function (newValue, devName, cellName) {
       log("acVegOff  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       log("acVegOff  newValue={}, devName={}, cellName={}", newValue, devName, cellName);
       dev["wb-mir_76/Play from ROM2"] = true; // выключить
       dev["wb-mir_76/Play from ROM2"] = true; // turn off
     }
     }
   });
   });
Строка 1643: Строка 1310:
</syntaxhighlight>
</syntaxhighlight>
== Полезные ссылки ==
== Полезные ссылки ==
* [[Wb-rules | Краткое описание wb-rules на wiki]]
* [[Wb-rules | Brief description of wb-rules on wiki]]
* [https://github.com/wirenboard/wb-rules Полное описание wb-rules на Github]
* [https://github.com/wirenboard/wb-rules Full description of wb-rules on Github]
</div>
wb_editors
14 355

правок