Перейти к содержанию

Навигация

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

12 803 байта добавлено ,  1 месяц назад
(не показаны 32 промежуточные версии 6 участников)
Строка 1: Строка 1:
{{DISPLAYTITLE: Примеры правил}}
<languages/>
<languages/>
<translate>
<translate>
=== Слежение за контролом === <!--T:20-->
<!--T:255-->
{{DISPLAYTITLE: Примеры правил}}
 
== Общая информация ==
Здесь вы найдёте учебные примеры скриптов, написанных для движка правил '''[[wb-rules| wb-rules]]'''.
 
Алгоритмы в примерах предельно просты и не учитывают многих факторов которые могут возникнуть в реальности. Поэтому используйте эту библиотеку только как учебный материал, а не источник готовых скриптов для реальных проектов.
 
== Виртуальное устройство ==
 
Виртуальное устройство можно использовать для объединения каналов, задания особой логики для устройства или просто так для красоты.
 
Пример ниже создаст виртуальное устройство с именем '''deviceName''' и двумя контролами '''value''' и '''state'''. А благодаря правилу с '''whenChanged''', значение контрола '''state''' будет менять в зависимости от значение контрола '''value'''.
 
<syntaxhighlight lang="ecmascript">
deviceName = 'my-virtual-device';
 
defineVirtualDevice(deviceName, {
    title: {'en': 'My Virtual Device', 'ru': 'Мое виртуальное устройство'} ,
    cells: {
      value: {
        title: {'en': 'Value', 'ru': 'Значение'},
        type: "range",
        value: 1,
        max: 3,
        min: 1
      },
      state: {
        title: {'en': 'State', 'ru': 'Состояние'},
        type: "value",
        value: 1,
        enum:{
          1: {'en': 'Normal', 'ru': 'В норме'},
          2: {'en': 'Warning', 'ru': 'Внимание'},
          3: {'en': 'Crash', 'ru': 'Авария'}} 
      },
    }
});
 
defineRule({
  whenChanged: deviceName+"/value",
  then: function (newValue, devName, cellName) {
dev[deviceName+"/state"] = newValue;
  }
});
 
</syntaxhighlight>
 
== Слежение за контролом == <!--T:20-->


<!--T:21-->
<!--T:21-->
Строка 11: Строка 58:


<!--T:23-->
<!--T:23-->
В примере датчик движения подключен к входу «сухой контакт», контрол типа «switch». Сирена подключена к встроеному реле Wiren Board, а лампа - через релейный блок по Modbus.  Когда вход типа "сухой контакт" (выход датчика движения) замкнут, то на лампу и реле подаётся «1», когда выключен - «0».
В примере датчик движения подключен к входу «сухой контакт», контрол типа «switch». Сирена подключена к встроеному реле Wiren Board, а лампа через релейный блок по Modbus.  Когда вход типа «сухой контакт» (выход датчика движения) замкнут, то на лампу и реле подаётся «1», когда выключен «0».


<!--T:24-->
<!--T:24-->
Строка 23: Строка 70:
   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;


   <!--T:27-->
   <!--T:27-->
Строка 52: Строка 99:
   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;


   <!--T:32-->
   <!--T:32-->
Строка 60: Строка 107:
</syntaxhighlight>
</syntaxhighlight>


=== Детектор движения c таймаутом === <!--T:34-->
== Мастер-выключатель с восстановлением последнего состояния == <!--T:250-->


<!--T:35-->
На вход контроллера подключен мастер-выключатель, который, при переключении, отключает все устройства, указанные в соответствующем правиле. При повторном нажатии на выключатель, устройствам возвращается первоначальное состояние.
На вход D2 подключен детектор движения с выходом «сухой контакт». При обнаружении движения он замыкает D2 и GND, и на соответствующем канале <code>wb-gpio/D2_IN</code> появляется статус «1».
 
Подключение осуществляется к контакту A1 и 5V на контроллере. При замыкании на соответствующем канале <code>wb-gpio/A1_IN</code>, состояние меняется, и срабатывает правило.


<!--T:37-->
Для управления через веб-интерфейс создано виртуальное устройство, отображаемое на вкладке '''Устройства'''.
Освещение подключено через встроенное реле, соответствующий канал <code>wb-gpio/Relay_1</code>.


<!--T:36-->
Первоначальные состояния устройств сохраняются в [https://github.com/wirenboard/wb-rules#%D0%BF%D0%BE%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%BD%D0%BE%D0%B5-%D1%85%D1%80%D0%B0%D0%BD%D0%B8%D0%BB%D0%B8%D1%89%D0%B5 постоянном хранилище]. Переменные в постоянном хранилище записываются на флеш-память, что обеспечивает доступ к ним после перезагрузки контроллера.
 
<syntaxhighlight lang="ecmascript">
defineVirtualDevice("power_off", {
    title: "Мастер-выключатель",
    cells: {
        power_off: {
            type: "pushbutton"
        },
    }
});
 
var ps = new PersistentStorage("power-storage", { global: true });
var lights = ["wb-mdm3_50/K1", "wb-mdm3_50/K2", "wb-mdm3_50/K3"];
 
var isPowerOff = true;
 
defineRule({
    whenChanged: ["wb-gpio/A1_IN", "power_off/power_off"],
    then: function (newValue, devName, cellName) {
        if (isPowerOff) {
            lights.forEach(function (light) {
                ps[light] = dev[light];
                dev[light] = false;
            });
        } else {
            lights.forEach(function (light) {
                dev[light] = ps[light];
            });
        }
        isPowerOff = !isPowerOff;
    }
});
</syntaxhighlight>
 
== Детектор движения c таймаутом == <!--T:34-->
 
<!--T:35-->
На вход D2 подключен детектор движения с выходом «сухой контакт». При обнаружении движения он замыкает D2 и GND, и на соответствующем канале <code>wb-gpio/D2_IN</code> появляется статус «1».
 
<!--T:37-->
Освещение подключено через встроенное реле, соответствующий канал <code>wb-gpio/Relay_1</code>.
 
<!--T:36-->
Правило работает так:
Правило работает так:
* когда движение появляется, свет включается. Если ранее был запущен тридцатисекундный таймер «на выключение», этот таймер отключается;
* когда движение появляется, свет включается. Если ранее был запущен тридцатисекундный таймер «на выключение», этот таймер отключается;
Строка 83: Строка 173:
     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);
Строка 96: Строка 186:
</syntaxhighlight>
</syntaxhighlight>


=== Создание однотипных правил === <!--T:43-->
== Создание однотипных правил == <!--T:43-->


<!--T:44-->
<!--T:44-->
Строка 109: Строка 199:
       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);
Строка 116: Строка 206:
               <!--T:46-->
               <!--T:46-->
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);
Строка 130: Строка 220:
</syntaxhighlight>
</syntaxhighlight>


=== Активация правила только в определённое время === <!--T:48-->
== Активация правила только в определённое время == <!--T:48-->


<!--T:49-->
<!--T:49-->
Строка 161: Строка 251:
     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) {
Строка 168: Строка 258:
    
    
           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);               
Строка 177: Строка 267:
</syntaxhighlight>
</syntaxhighlight>


=== Роллеты === <!--T:53-->
== Роллеты == <!--T:53-->


<!--T:54-->
<!--T:54-->
Строка 210: Строка 300:
   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 () {
Строка 219: Строка 309:
       <!--T:59-->
       <!--T:59-->
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);
     }
     }
Строка 227: Строка 317:
defineRule("roller_shutter_down_on" + suffix, {
defineRule("roller_shutter_down_on" + suffix, {
     asSoonAs: function() {
     asSoonAs: function() {
       return dev[relay_down_device][relay_down_control];
       return dev["relay_down_device/relay_down_control"];
     },
     },
     then: function () {
     then: function () {
Строка 235: Строка 325:
        
        
       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);
     }
     }
Строка 243: Строка 333:
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 () {
Строка 258: Строка 348:
       <!--T:63-->
       <!--T:63-->
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");
     }
     }
Строка 340: Строка 430:
     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; // Умножаем значение счетчика на количество литров/импульс и прибавляем корректировочное значение.
       dev["water_meters/water_meter_1"] = ((parseInt(newValue) - counterCorrection) * inpulseValue) + meterCorrection; // Умножаем значение счетчика на количество литров/импульс и прибавляем корректировочное значение.
       }
       }
     }
     }
Строка 346: Строка 436:
</syntaxhighlight>
</syntaxhighlight>


== Обработка счётчиков нажатий == <!--T:196-->
== Инвертирование значения контрола ==
[[Image:wb-rules-ex-buzzer-invert.png|300px|thumb|right|Пример устройств с вкладки Устройства]]
Правило ниже создаёт виртуальное устройство ''my-invert-buzzer'', с контролом ''disabled'', который инвертирует состояние контрола ''enabled'' системной пищалки ''Buzzer''.
<syntaxhighlight lang="ecmascript">
defineVirtualDevice('my-invert-buzzer', {
    title: 'Buzzer Invert' ,
    cells: {
      Disabled: {
        title: "disabled",
    type: "switch",
    value: !dev["buzzer/enabled"]
    }
    }
})
 
defineRule({
    whenChanged: ["buzzer/enabled"],
    then: function(newValue, devName, cellName) {
      dev["my-invert-buzzer/Disabled"] = !newValue;
    }
});
 
defineRule({
    whenChanged: ["my-invert-buzzer/Disabled"],
    then: function(newValue, devName, cellName){
        dev["buzzer/enabled"] = !newValue;
    }
});
</syntaxhighlight>
 
== Обработка счётчиков нажатий == <!--T:196-->
{{Anchor|press-actions}}
{{Anchor|press-actions}}
=== Описание ===
=== Описание ===
Строка 467: Строка 587:


=== Универсальный модуль для wb-rules === <!--T:214-->
=== Универсальный модуль для wb-rules === <!--T:214-->
Мы написали модуль для wb-rules [https://github.com/wirenboard/wb-community/tree/main/wb-press-actions wb-press-actions], который облегчает обработку нажатий в ваших скриптах.
Мы написали модуль для wb-rules [https://github.com/wirenboard/wb-community/tree/main/scripts/wb-press-actions wb-press-actions], который облегчает обработку нажатий в ваших скриптах.


== Датчик MSW v.3 == <!--T:215-->
== Датчик MSW v.3 == <!--T:215-->
Строка 492: Строка 612:


         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;
         }
         }
     }
     }
});
});
</syntaxhighlight>
</syntaxhighlight>
</div>
=== Max Motion === <!--T:220-->
"Max Motion" - максимальное значение датчика движения за N время. Время от 1 до 60 секунд можно выставить в 282 регистре. По умолчанию 10 секунд. При достижении Max Motion значения 50 проверяем достаточно ли освещена комната, если нет - включаем свет. Как только значение Max Motion упадет ниже 50 свет выключаем.


<!--T:221-->
Но когда устройств/правил много их целесообразно создавать одной функцией, передавая в нее разные параметры:  
<div class="NavFrame">
 
  <div class="NavContent">
<syntaxhighlight lang="ecmascript">
<syntaxhighlight lang="ecmascript">
defineRule("msw3_Motion", {
function ruleCO2 (devCO2, minCO2, maxCO2){
     whenChanged: "wb-msw-v3_97/Max Motion",
  log.debug("rule create", devCO2)
  defineRule ("ruleCO2"+devCO2, {
      whenChanged: devCO2+"/CO2",
      then: function(newValue, devName, cellName) {
        log.info("ruleCO2 " + devCO2 +" enter with", newValue)
        if (newValue < minCO2) {
          dev[devCO2+"/LED Glow Duration (ms)"] = 50;
          dev[devCO2+"/Green LED"] = true;
          dev[devCO2+"/Red LED"] = false;
          dev[devCO2+"/LED Period (s)"] = 3;
        }
        if ((newValue > minCO2) && (newValue < maxCO2)) {
          dev[devCO2+"/LED Glow Duration (ms)"] = 50;           
          dev[devCO2+"/Green LED"] = true;
          dev[devCO2+"/Red LED"] = true;
          dev[devCO2+"/LED Period (s)"] = 2;
        }
        if (newValue > maxCO2) {
          dev[devCO2+"/LED Glow Duration (ms)"] = 50;           
          dev[devCO2+"/Green LED"] = false;
          dev[devCO2+"/Red LED"] = true;
          dev[devCO2+"/LED Period (s)"] = 1;
        }
      }
  });
}
 
 
ruleCO2("wb-msw-v3_97", 650, 1000);
ruleCO2("wb-msw-v3_98", 650, 1000);
ruleCO2("wb-msw-v3_11", 500, 700);
</syntaxhighlight>
 
</div>
 
=== Max Motion === <!--T:220-->
"Max Motion" - максимальное значение датчика движения за N время. Время от 1 до 60 секунд можно выставить в 282 регистре. По умолчанию 10 секунд. При достижении Max Motion значения 50 проверяем достаточно ли освещена комната, если нет - включаем свет. Как только значение Max Motion упадет ниже 50 свет выключаем.
 
<!--T:221-->
<div class="NavFrame">
  <div class="NavContent">
<syntaxhighlight lang="ecmascript">
defineRule("msw3_Motion", {
     whenChanged: "wb-msw-v3_97/Max Motion",
     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;
         }
         }
     }
     }
Строка 667: Строка 826:
     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"] ;
         }
         }
     }
     }
Строка 680: Строка 839:
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;
   }
   }
});
});
Строка 690: Строка 849:
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;
   }
   }
});
});
Строка 722: Строка 881:
    type: "switch",
    type: "switch",
    value: false,
    value: false,
    },.......
    },
  }
})


<!--T:225-->
<!--T:225-->
Строка 749: Строка 910:


</syntaxhighlight>
</syntaxhighlight>
== Отправка команд по RS-485 == <!--T:99-->
== Отправка команд по RS-485 == <!--T:99-->


Строка 802: Строка 964:
<!--T:112-->
<!--T:112-->
<pre>
<pre>
root@wirenboard:~# mcedit /etc/wb-rules/rs485_cmd.js
nano /etc/wb-rules/rs485_cmd.js
</pre>
</pre>


Строка 826: Строка 988:
<!--T:116-->
<!--T:116-->
<pre>
<pre>
root@wirenboard:~# /etc/init.d/wb-rules restart
systemctl restart wb-rules
root@wirenboard:~# tail -f /var/log/messages
</pre>
<pre>
journalctl -u wb-rules -f
</pre>
</pre>


Строка 1036: Строка 1200:
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
{
{
"temperature_setpoint": 60,
"temperature_setpoint": 25,
"humidity_setpoint": 14
"humidity_setpoint": 14
}
}
Строка 1504: Строка 1668:
})()
})()
</syntaxhighlight>
</syntaxhighlight>
==Работа с JSON==
Движок wb-rules поддерживает стандартные функции языка JavaScript для работы с JSON:
*<code>JSON.stringify()</code> — преобразует объект в JSON-строку;
*<code>JSON.parse()</code> — преобразует JSON-строку в объект.
Более подробную информацию о функциях можно найти в учебнике [https://learn.javascript.ru/json JavaScript].
Эти функции требуются, когда вы получаете данные из другого сервиса в JSON-формате.
В приведенном примере создается виртуальное устройство с одной кнопкой и числовым параметром, который который хранится в виде JSON-строки. При нажатии на кнопку к значению параметра прибавляется 1.
<syntaxhighlight lang="bash">
defineVirtualDevice("JSON_test", {
    title: "JSON_device",
    cells: {
Button: {
    type: "pushbutton",
    value: false
},
    Json: {
        type : "text",
        value : JSON.stringify({param: 0}),
    },     
  }
});
defineRule("change_value", {
  whenChanged: "JSON_test/Button",
  then: function () {
    parameter = JSON.parse(dev["JSON_test/Json"]);
    parameter.param++;
    dev["JSON_test/Json"] = JSON.stringify(parameter)
    }
});
</syntaxhighlight>
==Работа с последовательным портом через RPC==
[[File:mqtt-rpc.png|300px|thumb|right|Работа с последовательным портом через RPC]]
Если устройство на шине работает по протоколу, который не поддерживается драйвером [[Wb-mqtt-serial_driver |wb-mqtt-serial]] можно формировать запросы вручную и отправлять их драйверу через [https://github.com/wirenboard/mqtt-rpc RPC-MQTT].
RPC-MQTT создает MQTT-топик для отправки запросов, и топик для чтения ответов от драйвера. Поэтому для его использования достаточно отправить запрос в нужный топик функцией <code>publish()</code> и прочитать ответ функцией <code>trackMqtt()</code>. Как узнать адреса топиков описано в [https://github.com/wirenboard/mqtt-rpc документации].
В примере написан скрипт на wb-rules для отправки Modbus-запроса устройству Wiren Board на шине RS-485.
Переменная <code>message</code> содержит Modbus-запрос, сформированный в соответствии со стандартом [[Modbus |Modbus RTU]].
Переменная <code>pathRPC</code> — это адрес MQTT-топика, в который отправляются запросы для драйвера wb-mqtt-serial. Для каждого сервиса используется свой топик, и узнать его адрес можно из документации на RPC-MQTT.
<syntaxhighlight lang="bash">
var pathRPC = "/rpc/v1/wb-mqtt-serial/port/Load/";  //Адрес топика в который отправляется запрос
var modbusPort = "/dev/ttyRS485-1";
var modbusSpeed = 9600;
var modbusParity = "N";
var modbusStopbit = 2;
var message = "E0300C8000644C9";
var clientID = "testRPC";
function requestRPC(modbusPort, modbusSpeed, modbusParity, modbusStopbit, clientID, requiestID, messageType, message, responseSize){
var strJson = JSON.stringify({params: {response_size: responseSize, format: messageType, path: modbusPort, baud_rate: modbusSpeed, parity: modbusParity, "data_bits" : 8, "stop_bits" : modbusStopbit, "msg": message}, "id" : requiestID});
  log.info("strJson =", strJson);
  publish(pathRPC+clientID, strJson, 2, false)
};
trackMqtt(pathRPC+clientID+"/reply", function(message){
  log.info("name: {}, value: {}".format(message.topic, message.value))
});
requestRPC(modbusPort, modbusSpeed, modbusParity, modbusStopbit, clientID, 1, "HEX", message, 8)
</syntaxhighlight>
Если запрос отправлен без ошибок, то в лог будет выведено сообщение вида:
<syntaxhighlight lang="bash">
name: /rpc/v1/wb-mqtt-serial/port/Load/testRPC/reply,
value: {"error":null,"id":1,"result":{"response":"0e030400002569df"}}
</syntaxhighlight>
== Получение SMS ==
В примере с периодом в 1 секунду выводится в лог вся информация о последнем сообщении. Полученные SMS будут в capturedOutput. Пример из [https://support.wirenboard.com/t/wb7-modem-rabota-s-sms-soobshheniyami/18159 темы на портале].
<syntaxhighlight lang="bash">
var period = 1000;
setInterval(function() {
    runShellCommand("mmcli --modem wbc --messaging-list-sms --output-keyvalue | grep length | cut -f2 -d':'", {
        captureOutput: true,
        exitCallback: function(exitCode, capturedOutput) {
            if (exitCode === 0) {
                runShellCommand("mmcli --modem wbc --sms " + (parseInt(capturedOutput) - 1).toString(), {
                    captureOutput: true,
                    exitCallback: function(exitCode, capturedOutput) {
                        if (exitCode === 0) {
                            log(capturedOutput);
                            return;
                        }
                    }
                });
                return;
            }
        }
    });
}, period);
</syntaxhighlight>
== Полезные ссылки == <!--T:190-->
== Полезные ссылки == <!--T:190-->
* [[Wb-rules | Краткое описание wb-rules на wiki]]
* [[Wb-rules | Краткое описание wb-rules на wiki]]
* [https://github.com/wirenboard/wb-rules Полное описание wb-rules на Github]
* [https://github.com/wirenboard/wb-rules Полное описание wb-rules на Github]
</translate>
</translate>