Wb-jscript: различия между версиями
(Перенаправление на Wb-rules) Метка: новое перенаправление |
Brainroot (обсуждение | вклад) |
||
(не показано 17 промежуточных версий 4 участников) | |||
Строка 1: | Строка 1: | ||
# | == Введение == | ||
Задача автоматизации - это упростить человеку жизнь. “Умный дом” - это, конечно, частный случай. Но полезный. | |||
Попытаемся применить скрипты контроллера WB (Wiren Board 6) для управления. | |||
Текст ниже предназначен тем, кто не имеет опыта программирования, но хочет научиться. | |||
== Используемое оборудование == | |||
* [[Wiren_Board_6|Контроллер]] | |||
* [[WBIO-DI-WD-14_I/O_Module|Модуль WBIO-DI-WD-14]] | |||
* [[WBIO-DO-R1G-16_I/O_Module|WBIO-DO-R1G-16]] | |||
---- | |||
''В названиях “DI” - Digital Input “DO” - Output соответственно.'' | |||
== Программирование == | |||
=== Скрипт === | |||
Скриптом называется обыкновенный текстовый файл. Для того чтобы он выполнялся движком [[Движок_правил_wb-rules|wb-rules]] нужно выполнить два условия: | |||
# Имя файла должно заканчиваться на '''.js''' | |||
# Файл должен располагаться в каталоге '''/etc/wb-rules''' | |||
[[Веб-интерфейс_Wiren_Board|Веб-интерфейс]] контроллера имеет встроенный редактор скриптов, доступный из его главного меню по ссылке '''"Rules"''' | |||
== Выполнение скриптов == | |||
Только что созданный скрипт после нажатия кнопки "Save" (и при запуске wb-rules) сразу же выполнится. То есть, будут созданы все переменные, правила, таймеры. И дальнейшее поведение скрипта будет определяться только событиями, как внешними (изменения состояния устройств, на которые "подписаны" правила) так и таймерами. | |||
== Переменные == | |||
Где хранить значения, а также строки и все остальное, включая ссылки на объекты? Именно в переменных. | |||
Можно представить каждую переменную как коробку. Подписанную коробку. | |||
Подпись - это имя переменной, а содержимое коробки - это ее значение. | |||
Кроме "простых" переменных еще используются массивы. Массив - это "стопка" значений, которые определяются одним именем переменной и "номером" в стопке. | |||
''Еще есть структуры (объекты), но о них - позже.'' | |||
<blockquote>'''Важно:''' JS, по умолчанию, при присвоении переменной одного типа значения другого типа - меняет тип переменной. Иногда это вызывает неожиданное поведение.</blockquote> | |||
Типы переменных в JS: | |||
* String: представляет строку | |||
* Number: представляет числовое значение | |||
* Boolean: представляет логическое значение true или false. | |||
* undefined: указывает, что значение не установлено | |||
* null: указывает на неопределенное значение | |||
Ниже попробуем создать первый скрипт и поймем значение типов. | |||
== Логи == | |||
Использование логов для отладки - бесценно. Иметь возможность в любом месте скрипта записать текущее значение переменной, состояние устройства очень помогает. | |||
Логи в WB двух типов - с записью в файл (/var/log/mesages) и в mqtt топик. | |||
Лог вызывается такой командой: | |||
log.{debug,info,warning,error}(fmt, [arg1 [, ...]]) | |||
Научимся ими пользоваться, а заодно, и напишем первый скрипт. | |||
В меню “Rules” нажимаем “New” и в поле для имени, вверху пишем “logs_and_vars_test.js” | |||
И в поле скрипта вставляем: | |||
<syntaxhighlight lang="ecmascript"> | |||
//logs_and_vars_test.js | |||
//Просто комментарий. Начинается с двойного слеша "//" | |||
var testvar1; //Переменная "testvar1" Ничего не присваиваем при объявлении(создании), "пустая" | |||
log.info("Тип и значение переменной testvar1", typeof(testvar1), testvar1); // Тип (и значение) undefined | |||
testvar1 = "yellow submarine"; // Присвоим строку | |||
log.info("Тип и значение переменной testvar1", typeof(testvar1), testvar1); | |||
testvar1 = 42; //Присвоим число | |||
log.info("Тип и значение переменной testvar1", typeof(testvar1), testvar1); | |||
testvar1 = false; //Булево (true/false) | |||
log.info("Тип и значение переменной testvar1", typeof(testvar1), testvar1); | |||
testvar2 = "red submarine"; //Сразу при объявлении присваиваем значение | |||
log.info("Тип и значение переменной testvar2", typeof(testvar2), testvar2); | |||
testvar1 = testvar2; //Тип testvar1 - булево. testvar2 - строка | |||
log.info("Тип и значение переменной testvar1", typeof(testvar1), testvar1); // при присвоении тип поменялся. | |||
</syntaxhighlight> | |||
<blockquote>''Не забывайте '''пустую''' строку в конце скрипта.</blockquote> | |||
<br>Прежде чем сохранять, давайте зададимся вопросом “как же логи читать?” | |||
Два (даже три) способа. | |||
* Самый простой: нажимаем на кнопку с символом гаечного ключа. Она находится в нижнем правом углу окна редактора скриптов. | |||
[[Файл:Wb-jscript-Logs-1.png|200px|thumb|center|Кнопка для логов]] | |||
Нажимаем - выдвигается консоль. Пока пустая, но после нажатия ''кнопки "Save"'' сюда выводятся сообщения. | |||
[[Файл:Wb-jscript-Logs-2.png|400px|thumb|center|Панель лога]] | |||
* Чуть сложнее: открываем ssh сессию на контроллере и вводим | |||
<syntaxhighlight lang="bash"> | |||
tail -f /var/log/messages |grep wb-rules | |||
</syntaxhighlight> | |||
Команда просматривает файл и при появлении в нем строчек с "'''wb-rules'''" | |||
Нажмем опять ''кнопку "Save"'' - выводит их в '''stdout''' (на экран) | |||
[[Файл:Wb-jscript-Logs-bash.png|400px|thumb|center|Логи в SSH сессии]] | |||
<blockquote> | |||
Чтобы кнопка "Save" стала вновь активной, надо что-нибудь изменить в окне редактора. Например, добавить пробел. | |||
</blockquote> | |||
Можно убедиться, что скрипт выполняется и даже совершает полезное действие - выводит сообщения. | |||
=== Как определить тип === | |||
Функция <syntaxhighlight lang="ecmascript">typeof</syntaxhighlight> принимает в качестве аргумента (то, что в скобках) '''переменную''' и возвращает нам ее '''тип''' | |||
Если выполнить код: | |||
<syntaxhighlight lang="ecmascript"> | |||
variable1 = "yellow submarine"; | |||
variable2 = typeof(variable1); | |||
</syntaxhighlight> | |||
То <syntaxhighlight lang="ecmascript">variable2</syntaxhighlight> будет иметь тип "'''string'''" и значение "'''yellow submarine'''" | |||
2do: Дописать про форматирование вывода логов вида log("Инфо текст {} {} {}".format(var1, var2, var3)); | |||
== Условия == | |||
Очень часто нужно что-нибудь с чем-то сравнить. Например, температуру с желаемой (с ''уставкой'' на тайном языке наладчиков-проектировщиков). | |||
Напишем простой пример, в котором сравним два значения. | |||
<syntaxhighlight lang="ecmascript"> | |||
//if_then.js | |||
//Просто комментарий. Начинается с двойного слеша "//" | |||
var t_real =20; //Переменная в которой будет хранитьтся измеренная (реальная) температура | |||
var t_ust = 22; //Переменная в которой хранится уставка (желаемая) температура | |||
if (t_real > t_ust) { //В "()"скобках - условие. | |||
log.info("Температура", t_real, "БОЛЬШЕ уставки", t_ust); | |||
} | |||
</syntaxhighlight> | |||
<blockquote>''Не забывайте '''пустую''' строку в конце скрипта.</blockquote> | |||
=== Использование === | |||
Сама конструкция условий основана на простой вещи: Если то, что в круглых скобках после оператора "if" ''верно'' - код в "{}" выполнитя | |||
Надо отвлечься на понятие - "верно" то есть '''истина''', '''true''' | |||
Если мы говорим о условиях - сразу перечислим самые распростарненные: | |||
* '''>''' - больше '''true''' когда ( 5 > 3 ) | |||
* '''<''' - меньше '''true''' когда ( 1 < 3 ) | |||
* '''>=''' - больше или равно '''true''' когда ( 5 >= 3) и когда ( 5 >= 5 ) | |||
* '''==''' - равно '''true''' когда ( 5 == 5) '''Внимание! про == ниже''' | |||
* '''||''' - ИЛИ '''true''' когда ( true || true ), кода ( true || false ), хоть одно из условий true | |||
* '''&&''' - И '''true''' когда ( true && true ), кода оба true | |||
И про "равно" "'''=='''": | |||
<syntaxhighlight lang="ecmascript"> | |||
//if_then_eq.js | |||
var test1 = 2; | |||
var test2 = 3; | |||
if (test1 = test2) { | |||
log.info("Выполняется! А почему?!"); | |||
} | |||
log.info("test1", test1); | |||
log.info("test2", test2); | |||
</syntaxhighlight> | |||
Все просто. Для того чтобы определить ''истинность'' условия компилятор '''выполняет''' выражение в скобках. Первой переменной можно присвоить вторую? Можно! Все, условие выполнено. Поэтому не надо использовать "=" в условиях. Только "==". | |||
Что делать, когда надо выполнять разные действия в зависимости от условия? Оператор '''else'''синтаксис ниже: | |||
<syntaxhighlight lang="ecmascript"> | |||
//if_then_else.js | |||
var t_real = 18; //Переменная в которой будет хранитьтся измеренная (реальная) температура | |||
var t_ust = 22; //Переменная в которой хранится уставка (желаемая) температура | |||
if (t_real > t_ust) { //В "()"скобках - условие. | |||
log.info("Температура", t_real, "БОЛЬШЕ уставки", t_ust); | |||
} | |||
else { //Если условие НЕ выполняется | |||
log.info("Температура", t_real, "МЕНЬШЕ уставки", t_ust); | |||
} | |||
</syntaxhighlight> | |||
=== Отладка === | |||
Если условие не работает так как нам надо - то: | |||
* Проверяем '''[[Wb-jscript#.D0.9A.D0.B0.D0.BA_.D0.BE.D0.BF.D1.80.D0.B5.D0.B4.D0.B5.D0.BB.D0.B8.D1.82.D1.8C_.D1.82.D0.B8.D0.BF |тип]]''' переменных перед условием | |||
<syntaxhighlight lang="ecmascript"> | |||
//if_then_types.js | |||
var test1 = 4; | |||
var test2 = "aaa"; //Переменная тип string | |||
log.info("перед условием"); | |||
if (test1 > test2) { //В "()"скобках - условие. | |||
log.info("Больше"); | |||
} | |||
</syntaxhighlight> | |||
Сравнивать переменные разных типов - некорректно. | |||
Выведем типы чтобы оценить возможность сравения: | |||
<syntaxhighlight lang="ecmascript"> | |||
//if_then_types_1.js | |||
var test1 = 4; | |||
var test2 = "aaa"; //Переменная тип string | |||
log.info("перед условием. Тип test1", typeof(test1), "Тип test2", typeof(test2)); | |||
if (typeof(test1) !== typeof(test2)) { //А вот типы сравнивать - можно. | |||
log.info("Типы разные"); | |||
} | |||
else { | |||
log.info("Типы одинаковые"); | |||
} | |||
if (test1 && test2) { //В "()"скобках - условие. | |||
log.info("И - работает, потому что обе переменные содержат отличное от нуля"); | |||
} | |||
</syntaxhighlight> | |||
<blockquote>"!" - это модификатор "НЕ" для логических условий. !true==false</blockquote> | |||
== Управление оборудованием == | |||
"Управлять" - значит получать состояния (входы) и реагировать на них, изменяя состояния выходов. | |||
Научиимся первому. | |||
=== Входы и правила === | |||
[https://wirenboard.com/wiki/WBIO-DI-WD-14_I/O_Module#.D0.9C.D0.BE.D0.BD.D1.82.D0.B0.D0.B6 Подключим модуль] [https://wirenboard.com/wiki/WBIO-DI-WD-14_I/O_Module WBIO-DI-WD-14] и [https://wirenboard.com/wiki/%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D0%B8_%D0%B2%D0%B2%D0%BE%D0%B4%D0%B0-%D0%B2%D1%8B%D0%B2%D0%BE%D0%B4%D0%B0#.D0.90.D0.BA.D1.82.D0.B8.D0.B2.D0.B8.D1.80.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D0.B5_.D0.B2_.D0.B2.D0.B5.D0.B1-.D0.B8.D0.BD.D1.82.D0.B5.D1.80.D1.84.D0.B5.D0.B9.D1.81.D0.B5_.D0.BA.D0.BE.D0.BD.D1.82.D1.80.D0.BE.D0.BB.D0.BB.D0.B5.D1.80.D0.B0 настроим] его. | |||
В [https://wirenboard.com/wiki/%D0%92%D0%B5%D0%B1-%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81_Wiren_Board#Devices_.28.D0.A3.D1.81.D1.82.D1.80.D0.BE.D0.B9.D1.81.D1.82.D0.B2.D0.B0.29 Devices] модуль отображается так: [[Файл:Wb-jscript-devices-WD-14.png|200px|thumb|center|Входы WD-14]] | |||
Входы модуля имеют названия от '''EXT1_IN1''' до '''EXT1_IN14'''. "EXT1" - потому что модуль ''первый'' от контроллера. Если подключить еще один такой же его названия входов будут начинаться с "EXT2". | |||
При замыкании входа (возьмем EXT1_IN14) на клемму iGnd состояние входа меняется:[[Файл:Wb-jscript-devices-WD-14-IN14-true.png|100px|thumb|center|Вход EXT1_IN14 активен]] | |||
Для того чтобы использовать устройство (вход или выход) в скриптах мы должны знать как к ним обращаться. Как посмотреть имена проще всего? | |||
Три пути: | |||
* Открыть в веб-интерфейсе '''MQTTChannels''' [[Файл:Wb-jscript-MQTTChannels.png|200px|thumb|left|Каналы MQTT]] | |||
* Открыть в веб-интерфейсе '''Devices''' и щелкнуть мышью на имени:[[Файл:Wb-jscript_Devices_name.png|200px|thumb|left| Всплывающее имя в Devices]] И имя уже будет скопировано в буфер обмена. | |||
* Выполнить в консоли команду <syntaxhighlight lang="bash">mosquitto_sub -v -t /#</syntaxhighlight>[https://wirenboard.com/wiki/MQTT Про MQTT] | |||
Напомню, что в контроллере используется '''событийная''' модель, то есть действовать, реагировать будет на '''изменения''' состояния. | |||
Для демонстрации создаем новый скрипт | |||
<syntaxhighlight lang="ecmascript"> | |||
//wd-14_in_14.js | |||
var inputName = "wb-gpio/EXT1_IN14"; //Сохраним в переменной имя входа. | |||
defineRule("wd-14_in_14", { //название правила | |||
whenChanged: inputName, //при изменении указанного значения | |||
then: function (newValue, devName, cellName) { //выполняй следующие действия | |||
log.info("newValue", newValue, "devName", devName, "cellName", cellName); //Это лог. | |||
} | |||
}); | |||
</syntaxhighlight> | |||
И сохраним его. После сохранения ничего не происходит. Почему? | |||
Как и писал выше - ключевое слово '''"событие"'''. Мы [https://wirenboard.com/wiki/MQTT#.D0.9F.D1.80.D0.B8.D0.BC.D0.B5.D1.80_.D0.BF.D0.BE.D0.B4.D0.BF.D0.B8.D1.81.D0.BA.D0.B8 "подписались"] на нужный нам топик MQTT и теперь правило сработает при его изменении. | |||
Замкнем-разомкнем клемму '''"14"''' модуля [https://wirenboard.com/wiki/WBIO-DI-WD-14_I/O_Module WD-14] на его клемму '''"iGnd"''': | |||
[[Файл:Wb-jscript_input_rule_1.png|350px|thumb|center|Правило сработало]] | |||
То есть конструкция (синтаксис) правила такова: | |||
<syntaxhighlight lang="ecmascript"> | |||
defineRule("wd-14_in_14", { //название (то, что в кавычках). Можно использовать переменную. Правил с одинаковыми названиями быть не должно. | |||
whenChanged: "wb-gpio/EXT1_IN14", //Имя топика, на который подписываемся. Можно "строкой", можно переменной | |||
then: function (newValue, devName, cellName) { //Как и в конструкции if-then. Но в качестве выполняемых операторов - функция. | |||
log.info("newValue", newValue, "devName", devName, "cellName", cellName); //Это лог. Тут мы видим что в функцию передается как НОВОЕ значение топика так и имя устройстви с именем входа. Зачем, если и так знаем на что была подписка? Об этом дальше. | |||
} | |||
}); | |||
</syntaxhighlight> | |||
===Циклы=== | |||
Как выполнить что-нибудь несколько раз? Для этого существует конструкция "цикл". | |||
В JS описывается так: | |||
'''for ([Счетчик]; [условие]; [выражение]){Операторы}''' | |||
<blockquote>"Операторы - это часть кода, которая будет выполняться несколько раз, от настроек цикла"</blockquote> | |||
* '''Счетчик''' - выполняется один раз, обычно используют для ''обьявления переменной'' | |||
* '''условие''' - выполняется каждый цикл, если условие ''верно'' (''true'') то цикл повторяется. | |||
* '''выражение''' - выполняется каждый цикл, после выполнения операторов и до проверки '''условие'''. | |||
Попробуем? | |||
<syntaxhighlight lang="ecmascript"> | |||
//for.js | |||
for (i = 0; i<5; i++){ | |||
log.info("Переменная-счетчик i=", i); | |||
} | |||
</syntaxhighlight> | |||
В окне лога видно: | |||
<pre> | |||
2020-09-17 12:54:36Переменная-счетчик i= 0 | |||
2020-09-17 12:54:36Переменная-счетчик i= 1 | |||
2020-09-17 12:54:36Переменная-счетчик i= 2 | |||
2020-09-17 12:54:36Переменная-счетчик i= 3 | |||
2020-09-17 12:54:36Переменная-счетчик i= 4 | |||
</pre> | |||
Самое интересное, что ни один из параметров цикла не является обязательным. | |||
Пример: | |||
<syntaxhighlight lang="ecmascript"> | |||
//for_1.js | |||
var i = 0 | |||
for (; ; ){ | |||
log.info("Переменная-счетчик i=", i); | |||
i++; | |||
if (i > 5) {break}; // | |||
} | |||
</syntaxhighlight> | |||
<blockquote>Главное не допускать "бесконечных" циклов</blockquote> | |||
===Функции=== | |||
===Выходы=== | |||
== Таймеры == |
Версия 13:14, 24 сентября 2020
Введение
Задача автоматизации - это упростить человеку жизнь. “Умный дом” - это, конечно, частный случай. Но полезный. Попытаемся применить скрипты контроллера WB (Wiren Board 6) для управления. Текст ниже предназначен тем, кто не имеет опыта программирования, но хочет научиться.
Используемое оборудование
В названиях “DI” - Digital Input “DO” - Output соответственно.
Программирование
Скрипт
Скриптом называется обыкновенный текстовый файл. Для того чтобы он выполнялся движком wb-rules нужно выполнить два условия:
- Имя файла должно заканчиваться на .js
- Файл должен располагаться в каталоге /etc/wb-rules
Веб-интерфейс контроллера имеет встроенный редактор скриптов, доступный из его главного меню по ссылке "Rules"
Выполнение скриптов
Только что созданный скрипт после нажатия кнопки "Save" (и при запуске wb-rules) сразу же выполнится. То есть, будут созданы все переменные, правила, таймеры. И дальнейшее поведение скрипта будет определяться только событиями, как внешними (изменения состояния устройств, на которые "подписаны" правила) так и таймерами.
Переменные
Где хранить значения, а также строки и все остальное, включая ссылки на объекты? Именно в переменных. Можно представить каждую переменную как коробку. Подписанную коробку. Подпись - это имя переменной, а содержимое коробки - это ее значение.
Кроме "простых" переменных еще используются массивы. Массив - это "стопка" значений, которые определяются одним именем переменной и "номером" в стопке. Еще есть структуры (объекты), но о них - позже.
Важно: JS, по умолчанию, при присвоении переменной одного типа значения другого типа - меняет тип переменной. Иногда это вызывает неожиданное поведение.
Типы переменных в JS:
- String: представляет строку
- Number: представляет числовое значение
- Boolean: представляет логическое значение true или false.
- undefined: указывает, что значение не установлено
- null: указывает на неопределенное значение
Ниже попробуем создать первый скрипт и поймем значение типов.
Логи
Использование логов для отладки - бесценно. Иметь возможность в любом месте скрипта записать текущее значение переменной, состояние устройства очень помогает. Логи в WB двух типов - с записью в файл (/var/log/mesages) и в mqtt топик. Лог вызывается такой командой:
log.{debug,info,warning,error}(fmt, [arg1 [, ...]])
Научимся ими пользоваться, а заодно, и напишем первый скрипт. В меню “Rules” нажимаем “New” и в поле для имени, вверху пишем “logs_and_vars_test.js” И в поле скрипта вставляем:
//logs_and_vars_test.js
//Просто комментарий. Начинается с двойного слеша "//"
var testvar1; //Переменная "testvar1" Ничего не присваиваем при объявлении(создании), "пустая"
log.info("Тип и значение переменной testvar1", typeof(testvar1), testvar1); // Тип (и значение) undefined
testvar1 = "yellow submarine"; // Присвоим строку
log.info("Тип и значение переменной testvar1", typeof(testvar1), testvar1);
testvar1 = 42; //Присвоим число
log.info("Тип и значение переменной testvar1", typeof(testvar1), testvar1);
testvar1 = false; //Булево (true/false)
log.info("Тип и значение переменной testvar1", typeof(testvar1), testvar1);
testvar2 = "red submarine"; //Сразу при объявлении присваиваем значение
log.info("Тип и значение переменной testvar2", typeof(testvar2), testvar2);
testvar1 = testvar2; //Тип testvar1 - булево. testvar2 - строка
log.info("Тип и значение переменной testvar1", typeof(testvar1), testvar1); // при присвоении тип поменялся.
Не забывайте пустую строку в конце скрипта.
Прежде чем сохранять, давайте зададимся вопросом “как же логи читать?”
Два (даже три) способа.
- Самый простой: нажимаем на кнопку с символом гаечного ключа. Она находится в нижнем правом углу окна редактора скриптов.
Нажимаем - выдвигается консоль. Пока пустая, но после нажатия кнопки "Save" сюда выводятся сообщения.
- Чуть сложнее: открываем ssh сессию на контроллере и вводим
tail -f /var/log/messages |grep wb-rules
Команда просматривает файл и при появлении в нем строчек с "wb-rules" Нажмем опять кнопку "Save" - выводит их в stdout (на экран)
Чтобы кнопка "Save" стала вновь активной, надо что-нибудь изменить в окне редактора. Например, добавить пробел.
Можно убедиться, что скрипт выполняется и даже совершает полезное действие - выводит сообщения.
Как определить тип
Функция
typeof
принимает в качестве аргумента (то, что в скобках) переменную и возвращает нам ее тип
Если выполнить код:
variable1 = "yellow submarine";
variable2 = typeof(variable1);
То
variable2
будет иметь тип "string" и значение "yellow submarine"
2do: Дописать про форматирование вывода логов вида log("Инфо текст {} {} {}".format(var1, var2, var3));
Условия
Очень часто нужно что-нибудь с чем-то сравнить. Например, температуру с желаемой (с уставкой на тайном языке наладчиков-проектировщиков). Напишем простой пример, в котором сравним два значения.
//if_then.js
//Просто комментарий. Начинается с двойного слеша "//"
var t_real =20; //Переменная в которой будет хранитьтся измеренная (реальная) температура
var t_ust = 22; //Переменная в которой хранится уставка (желаемая) температура
if (t_real > t_ust) { //В "()"скобках - условие.
log.info("Температура", t_real, "БОЛЬШЕ уставки", t_ust);
}
Не забывайте пустую строку в конце скрипта.
Использование
Сама конструкция условий основана на простой вещи: Если то, что в круглых скобках после оператора "if" верно - код в "{}" выполнитя Надо отвлечься на понятие - "верно" то есть истина, true Если мы говорим о условиях - сразу перечислим самые распростарненные:
- > - больше true когда ( 5 > 3 )
- < - меньше true когда ( 1 < 3 )
- >= - больше или равно true когда ( 5 >= 3) и когда ( 5 >= 5 )
- == - равно true когда ( 5 == 5) Внимание! про == ниже
- || - ИЛИ true когда ( true || true ), кода ( true || false ), хоть одно из условий true
- && - И true когда ( true && true ), кода оба true
И про "равно" "==":
//if_then_eq.js
var test1 = 2;
var test2 = 3;
if (test1 = test2) {
log.info("Выполняется! А почему?!");
}
log.info("test1", test1);
log.info("test2", test2);
Все просто. Для того чтобы определить истинность условия компилятор выполняет выражение в скобках. Первой переменной можно присвоить вторую? Можно! Все, условие выполнено. Поэтому не надо использовать "=" в условиях. Только "==".
Что делать, когда надо выполнять разные действия в зависимости от условия? Оператор elseсинтаксис ниже:
//if_then_else.js
var t_real = 18; //Переменная в которой будет хранитьтся измеренная (реальная) температура
var t_ust = 22; //Переменная в которой хранится уставка (желаемая) температура
if (t_real > t_ust) { //В "()"скобках - условие.
log.info("Температура", t_real, "БОЛЬШЕ уставки", t_ust);
}
else { //Если условие НЕ выполняется
log.info("Температура", t_real, "МЕНЬШЕ уставки", t_ust);
}
Отладка
Если условие не работает так как нам надо - то:
- Проверяем тип переменных перед условием
//if_then_types.js
var test1 = 4;
var test2 = "aaa"; //Переменная тип string
log.info("перед условием");
if (test1 > test2) { //В "()"скобках - условие.
log.info("Больше");
}
Сравнивать переменные разных типов - некорректно. Выведем типы чтобы оценить возможность сравения:
//if_then_types_1.js
var test1 = 4;
var test2 = "aaa"; //Переменная тип string
log.info("перед условием. Тип test1", typeof(test1), "Тип test2", typeof(test2));
if (typeof(test1) !== typeof(test2)) { //А вот типы сравнивать - можно.
log.info("Типы разные");
}
else {
log.info("Типы одинаковые");
}
if (test1 && test2) { //В "()"скобках - условие.
log.info("И - работает, потому что обе переменные содержат отличное от нуля");
}
"!" - это модификатор "НЕ" для логических условий. !true==false
Управление оборудованием
"Управлять" - значит получать состояния (входы) и реагировать на них, изменяя состояния выходов. Научиимся первому.
Входы и правила
Подключим модуль WBIO-DI-WD-14 и настроим его.
В Devices модуль отображается так:
Входы модуля имеют названия от EXT1_IN1 до EXT1_IN14. "EXT1" - потому что модуль первый от контроллера. Если подключить еще один такой же его названия входов будут начинаться с "EXT2".
При замыкании входа (возьмем EXT1_IN14) на клемму iGnd состояние входа меняется:
Для того чтобы использовать устройство (вход или выход) в скриптах мы должны знать как к ним обращаться. Как посмотреть имена проще всего? Три пути:
- Открыть в веб-интерфейсе MQTTChannels
- Открыть в веб-интерфейсе Devices и щелкнуть мышью на имени: И имя уже будет скопировано в буфер обмена.
- Выполнить в консоли команду Про MQTT
mosquitto_sub -v -t /#
Напомню, что в контроллере используется событийная модель, то есть действовать, реагировать будет на изменения состояния. Для демонстрации создаем новый скрипт
//wd-14_in_14.js
var inputName = "wb-gpio/EXT1_IN14"; //Сохраним в переменной имя входа.
defineRule("wd-14_in_14", { //название правила
whenChanged: inputName, //при изменении указанного значения
then: function (newValue, devName, cellName) { //выполняй следующие действия
log.info("newValue", newValue, "devName", devName, "cellName", cellName); //Это лог.
}
});
И сохраним его. После сохранения ничего не происходит. Почему?
Как и писал выше - ключевое слово "событие". Мы "подписались" на нужный нам топик MQTT и теперь правило сработает при его изменении.
Замкнем-разомкнем клемму "14" модуля WD-14 на его клемму "iGnd":
То есть конструкция (синтаксис) правила такова:
defineRule("wd-14_in_14", { //название (то, что в кавычках). Можно использовать переменную. Правил с одинаковыми названиями быть не должно.
whenChanged: "wb-gpio/EXT1_IN14", //Имя топика, на который подписываемся. Можно "строкой", можно переменной
then: function (newValue, devName, cellName) { //Как и в конструкции if-then. Но в качестве выполняемых операторов - функция.
log.info("newValue", newValue, "devName", devName, "cellName", cellName); //Это лог. Тут мы видим что в функцию передается как НОВОЕ значение топика так и имя устройстви с именем входа. Зачем, если и так знаем на что была подписка? Об этом дальше.
}
});
Циклы
Как выполнить что-нибудь несколько раз? Для этого существует конструкция "цикл". В JS описывается так: for ([Счетчик]; [условие]; [выражение]){Операторы}
"Операторы - это часть кода, которая будет выполняться несколько раз, от настроек цикла"
- Счетчик - выполняется один раз, обычно используют для обьявления переменной
- условие - выполняется каждый цикл, если условие верно (true) то цикл повторяется.
- выражение - выполняется каждый цикл, после выполнения операторов и до проверки условие.
Попробуем?
//for.js
for (i = 0; i<5; i++){
log.info("Переменная-счетчик i=", i);
}
В окне лога видно:
2020-09-17 12:54:36Переменная-счетчик i= 0 2020-09-17 12:54:36Переменная-счетчик i= 1 2020-09-17 12:54:36Переменная-счетчик i= 2 2020-09-17 12:54:36Переменная-счетчик i= 3 2020-09-17 12:54:36Переменная-счетчик i= 4
Самое интересное, что ни один из параметров цикла не является обязательным. Пример:
//for_1.js
var i = 0
for (; ; ){
log.info("Переменная-счетчик i=", i);
i++;
if (i > 5) {break}; //
}
Главное не допускать "бесконечных" циклов