translator, wb_editors
4544
правки
Matveevrj (обсуждение | вклад) |
|||
(не показано 17 промежуточных версий 5 участников) | |||
Строка 1: | Строка 1: | ||
<languages/> | <languages/> | ||
<translate> | <translate> | ||
<!--T: | <!--T:255--> | ||
{{DISPLAYTITLE: Примеры правил}} | {{DISPLAYTITLE: Примеры правил}} | ||
== Общая информация == | == Общая информация == | ||
Здесь вы найдёте учебные примеры скриптов, написанных для движка правил [[wb-rules| wb-rules]]. | Здесь вы найдёте учебные примеры скриптов, написанных для движка правил '''[[wb-rules| wb-rules]]'''. | ||
Алгоритмы в примерах предельно просты и не учитывают многих факторов которые могут возникнуть в реальности. Поэтому используйте эту библиотеку только как учебный материал, а не источник готовых скриптов для реальных проектов. | Алгоритмы в примерах предельно просты и не учитывают многих факторов которые могут возникнуть в реальности. Поэтому используйте эту библиотеку только как учебный материал, а не источник готовых скриптов для реальных проектов. | ||
== Виртуальное устройство == | |||
Виртуальное устройство можно использовать для объединения каналов, задания особой логики для устройства или просто так для красоты. | |||
Пример ниже создаст виртуальное устройство с именем '''deviceName''' и двумя контролами '''value''' и '''state'''. А благодаря правилу с '''whenChanged''', значение контрола '''state''' будет менять в зависимости от значение контрола '''value'''. | |||
Виртуальным устройствам и контролам можно присваивать русские имена, задавая '''title''' в виде <code>title: { en: ’Title’, ru: ’Заголовок’ }</code>, или через '''setTitle''' у контрола: <code>setTitle({ en: ’Title’, ru: ’Заголовок’ })</code>. | |||
Для значений параметров с типом '''value''' и '''text''' можно использовать перечисления '''enum''' в виде набора именованных констант. Перечисления удобно использовать, когда значение параметра может принимать ограниченное количество значений, например, дни недели. | |||
Чтобы задать перечисление используйте для нужного контрола параметр '''enum''' с набором пар <code>“ключ”: “значение”</code>. | |||
Если параметр имеет тип '''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:20--> | ||
Строка 67: | Строка 116: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== | == Мастер-выключатель с восстановлением последнего состояния == <!--T:250--> | ||
На вход контроллера подключен мастер-выключатель, который, при переключении, отключает все устройства, указанные в соответствующем правиле. При повторном нажатии на выключатель, устройствам возвращается первоначальное состояние. | |||
Подключение осуществляется к контакту A1 и 5V на контроллере. При замыкании на соответствующем канале <code>wb-gpio/A1_IN</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--> | |||
Правило работает так: | Правило работает так: | ||
* когда движение появляется, свет включается. Если ранее был запущен тридцатисекундный таймер «на выключение», этот таймер отключается; | * когда движение появляется, свет включается. Если ранее был запущен тридцатисекундный таймер «на выключение», этот таймер отключается; | ||
Строка 1117: | Строка 1209: | ||
<syntaxhighlight lang="bash"> | <syntaxhighlight lang="bash"> | ||
{ | { | ||
"temperature_setpoint": | "temperature_setpoint": 25, | ||
"humidity_setpoint": 14 | "humidity_setpoint": 14 | ||
} | } | ||
Строка 1152: | Строка 1244: | ||
<!--T:249--> | <!--T:249--> | ||
При нажатии кнопки Save в веб-интерфейсе, будет перезапускаться сервис wb-rules, а значения установок - записываться в правила. | При нажатии кнопки Save в веб-интерфейсе, будет перезапускаться сервис wb-rules, а значения установок - записываться в правила. | ||
Работает всё это через [https://github.com/wirenboard/json-editor json-editor]. | |||
== Сложные правила с расписаниями == <!--T:138--> | == Сложные правила с расписаниями == <!--T:138--> | ||
Строка 1620: | Строка 1714: | ||
} | } | ||
}); | }); | ||
</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> | </syntaxhighlight> | ||