diff --git a/scripts/json-editor_to_code/README.md b/scripts/json-editor_to_code/README.md new file mode 100644 index 0000000..de40a5e --- /dev/null +++ b/scripts/json-editor_to_code/README.md @@ -0,0 +1,693 @@ +# json-editor_to_code example + +
+ +
+ +An example implementation of a WB-rules code generator that: + +- Takes parameters from JSON-editor forms for multiple WB-rules (JavaScript scripts). +- Generates JavaScript code for multiple rules based on a Jinja template. + +This example demonstrates the implementation of configuring parameters for +multiple rules that control the buzzer in the WB 8.4 controller for periodic +activation through fields in the WEBUI, followed by generating the rules +based on these parameters. + + + ++ +
+ +Пример реализации генератора кода WB-rules который: + +- Берет параметры из форм json-editor для нескольких правил wb-rules (скриптов JavaScript). +- Генерирует на основе шаблона jinja код нескольких правил на JavaScript. + +В данном примере показана реализация конфигурации параметров нескольких +правил, которые настраивают buzzer (пишалку) +в контроллере wb 8.4 на переодическое включение через поля в WEBUI +и последующая генерация правил на основе данных параметров. + +## Схема пути генерации кода + +На схеме изображены этапы генерации кода wb-rules на основе данных полученных от пользователя: + ++ +
+ +Данную схему можно изучить тут:\ + +- Lucidchart: generate_workflow_diagram + +## Принцип работы со стороны пользователя + +Цель - дать пользователю способ генерировать wb-rules/виртальные устройства +по заранее написанному шаблону просто работая с графическими полями в WEBUI. + +Поля выглядит таким образом + ++ +
+ +1) Пользователь заходит в WEBUI контроллера Wirenboard +2) Меняет права доступа с Пользователь на Администратор +3) Заходит на страницу Настройки - Конфигурационные правила +4) Находит нужный шаблон в списке конфигов, например "Rule template: Buzzer pereodic beep" +5) Заполняет поля конфигуратора\ +Данная форма создается с помошью json-editor схемы +6) При необходимости добавляет новое правило в список (если шаблон предусматривает список правил) +7) Нажимает сверху кнопку "Записать" +- При нажатии введённые в поля свойства сохраняются в `*.conf` файле в виде `json` +- Событие изменения файла конфигураци автоматически ловит сисиемная утилита incron +- incron запускает python скрипт +- Скрипт генерирует код js на основе jinja шаблона и записывает в папку wb-rules +- Система правил подхватывает новые правила и автоматически выполняет их логику +8) Полученная польза - пользователь создал скрипты на js (правила) не написав ни строчки кода + +## Описание порядка реализации + +В данной инструкции предпологается что контроллер находится в чистом состоянии, поэтому поясняются все необходимые моменты по настройке с нуля. + +### 0. Предварительные требования +Предпологается что вы поверхностно слышали и понимаете смысл: +- JavaScript - язык программирования применяемый в wb-rules +- wb-rules - движек правил который используется для написания правил в контроллерах wirenboard +- json-editor - применяется для создания форм в WEBUI с помошью описания в json схемах +- python3 - язык программирования поможет нам связать сохраненные конфигурации json-editor с jinja2 +- jinja2 - шаблонизатор который мы используем для генерации wb-rules +Можно освоить в процессе данного мануала + +### 1. Продумать фукнционал +Перед тем как начать писать скрипт - нужно понять чего мы хотим. + +Прописать и продумать: + +- Примерную общую цель генерируемого скипта +- Используемые готовые виртуальные устройства или используемые выходы/протоколы +- Логику работы скрипта +- Какие нужны поля настроек для пользователя. + +Например: + +```text +Общий смысл: +Шаблон создает правила периодического писка зуммера в контроллере с определенной частотой. + +Используемые ресурсы контроллера: +Используем готовое стандартное системно виртуальное устройство buzzer у которого уже есть свойства buzzer/frequency, buzzer/enabled +Исходники buzzer можно посмотреть тут: +https://github.com/wirenboard/wb-rules-system/blob/c2d2480d0ea1d8194d3b3303bda174b60a9cf115/rules/buzzer.js + +Логика: +Хотим чтобы раз в несколько секунд включался и выключался buzzer с частотой звучания 3000 Гц + +Изменяемые поля будут такие: +Для всех правил устанавливается одно общее значение +- Громкости работы зуммера +Для каждого добавляемого инстанса генерируемого правила будут задаваться +- Статус правила, чтобы отдельное правило можно было отключить +- Период срабатывания, чтобы регулировать время писка зуммера +- Частота писка (Обратите внимание что высокие частоты люди уже не слышат) +``` + +### 2. Подключиться к контроллеру + +Для реализации задуманного нам понадобится подключение через кабель Ethernet rj-45 (получение ip по DHCP), так как нужны: + +- Доступ по ssh в терминале или SFTP в файловом менеджере - для создания и редактирования файлов на контроллере +- Доступ к WEBUI в браузере - для работы с формами +- Подключение контроллера к интернету - для установки пакетов питона + +Как это сделать описано для контроллера Wiren Board 8.4 в разделе: **Подключение к компьютеру** + + +Наличие интернета на контроллере проверьте вводом в SSH консоли команды +```terminal +$ ping 1.1.1.1 +``` + +### 3. Написать обычный скрипт (правило) +Перед тем как создавать генерируемый вариант правил - нам нужно написать статичный скрипт и отладить его работу.\ +Это необходимо, чтобы мы могли дальше переделать его в генерируемый вариант без параллельной отладки фукнционала скрипта. + +В данном примере мы создадим виртуальное устройство - buzzer_pereodic_beep которое будет иметь два состояния - включено или выключено. +Если включено - то будет изменять состояние buzzer раз в заданное колличество секунд (3с пищит, 3с молчит). + +Пример готового правила описан ниже, обратите внимане - так как правило по дефолту включено `enabled:value: true`, то после его создания buzzer сразу начнет пищать. + +Создайте новое правило на странице "Правила": http://10.200.200.1/#!/rules +```javascript +/* File: /etc/wb-rules/test_buzzer_periodic_4s.js */ + +defineVirtualDevice("buzzer_periodic_4s", { + title: "Test Buzzer", + cells: { + enabled: { + type: "switch", + value: true + } + } +}); + +defineRule("1",{ + asSoonAs: function () { + return dev["buzzer_periodic_4s/enabled"]; + }, + then: function () { + startTicker("timer_4s", 4000); + } +}); +defineRule("2",{ + when: function () { return timers.timer_4s.firing; }, + then: function () { + if (dev["buzzer_periodic_4s/enabled"] == true) { + dev["buzzer/volume"] = 1; + dev["buzzer/frequency"] = 300; + dev["buzzer/enabled"] = !dev["buzzer/enabled"]; + } else { + timers.timer_4s.stop(); + dev["buzzer/enabled"] = false; + } + } +}); + +``` + +Для отладки менять состояние правила можно как в самом коде руками, так и через добавленный в 2Панели" виджет `buzzer_periodic_4s/enabled`. + +### 4. Описать WEBUI +После того как простой статичный скрипт отлажен - можно приступить к реализации WEBUI для его настройки пользователем. + +**4.1. Создать файл схемы** +Тут описывается вид и поля WEBUI который будет использоваться для генерации правил +Файлы схем находятся тут: + +```text +/usr/share/wb-mqtt-confed/schemas/*.schema.json +``` + +Файлы схем для генерируемых лучше назвать по какому-то шаблону, например добавив вначало config_template-*. Префикс нужен для отличия от обычных правил: + +```text +config_template-.schema.json +``` + +- Например для шаблона переодического пишания создадим файл + +```path +/usr/share/wb-mqtt-confed/schemas/config_template-buzzer_pereodic_beep.schema.json +``` + +**4.2. Заполнить шаблон WEBUI обязательно указав** + +- Title - это имя отображается как название конфигурационного файла в WEBUI + +```json +"title": "Rule template: ", +``` + +Например + +```json +"title": "Rule template: Buzzer pereodic beep", +``` + +- Description - Описание отображается на странице конфига + +```json +"description": "Описание шаблона:+ +
+ +Проверить корректность генерации + +- Появились ли реально сгенерированные файлы в списке правил +- Какие у них имена +- Проверить содержание + +Внутри файла должно быть следующее содержание: + +```text +/* WARNING: This file is automatically generated. Do not modify manually! */ + +Test: + - template_postfix = buzz + - volume = 1 + - rule.frequency = 400 + - rule.enabled = True + - rule_period_s = 3 + - rule_user_rule_name = Buzzer_pereodic_beep_3s +``` + +### 6. Переделать статичный скрипт (правило) в шаблон jinja + +На этом шаге нам нужно заменить все места где мы хотим подставлять данные из WEBUI (json-edit). + +Обратите внимание, так как правило по дефолту включено - то сразу начнет пищать и не закончит пока вы не удалите правило. +Удалять правило нужно в момент когда buzzer выключен. +Это определеяется в параметре `enabled` - тут стоит `value: true`: +```javascript + enabled: { + type: "switch", + value: true + } +``` + +Пример шаблона jinja: + +```javascript +/* WARNING: This file is automatically generated. Do not modify manually! */ + +defineVirtualDevice("buzzer_periodic_{{ rule.period_s }}s", { + title: "Test Buzzer: {{ rule.user_rule_name }}", + cells: { + enabled: { + type: "switch", + value: {{ rule.enabled | lower }} + } + } +}); + +defineRule("1",{ + asSoonAs: function () { + return dev["buzzer_periodic_{{ rule.period_s }}s/enabled"]; + }, + then: function () { + startTicker("timer_{{ rule.period_s }}s", {{ rule.period_s }}000); + } +}); +defineRule("2",{ + when: function () { return timers.timer_{{ rule.period_s }}s.firing; }, + then: function () { + if (dev["buzzer_periodic_{{ rule.period_s }}s/enabled"] == true) { + dev["buzzer/volume"] = {{ volume }}; + dev["buzzer/frequency"] = {{ rule.frequency }}; + dev["buzzer/enabled"] = !dev["buzzer/enabled"]; + } else { + timers.timer_{{ rule.period_s }}s.stop(); + dev["buzzer/enabled"] = false; + } + } +}); + +``` + +### 7. Ручная проверка генерации скрипта +Для этого запустим скрипт вручную + +```terminal +$ python3 /mnt/data/root/generate_rule-buzzer_pereodic_beep.py +``` + +В результате мы должны получить файл скрипта следующего вида + +File: /etc/wb-rules/Buzzer_pereodic_beep_3s.buzz_tmpl_gen.js + +```javascript +/* WARNING: This file is automatically generated. Do not modify manually! */ + +defineVirtualDevice("buzzer_periodic_3s", { + title: "Test Buzzer: Buzzer_pereodic_beep_3s", + cells: { + enabled: { + type: "switch", + value: true + } + } +}); + +defineRule("1",{ + asSoonAs: function () { + return dev["buzzer_periodic_3s/enabled"]; + }, + then: function () { + startTicker("timer_3s", 3000); + } +}); +defineRule("2",{ + when: function () { return timers.timer_3s.firing; }, + then: function () { + if (dev["buzzer_periodic_3s/enabled"] == true) { + dev["buzzer/volume"] = 2; + dev["buzzer/frequency"] = 400; + dev["buzzer/enabled"] = !dev["buzzer/enabled"]; + } else { + timers.timer_3s.stop(); + dev["buzzer/enabled"] = false; + } + } +}); + +``` + + +### 8. Добавить правило в incron +incron это утилита которая поможет нам при изменениях сохраняемого конфига автоматически отслеживать изменения json конфиг файла. + +Она использует модуль ядра inotify - механизм уведомлений о событиях файловой системы, поэтому работает эффективно и не тратит много ресурсов в фоне. + +**8.1. Установить incron** + +```terminal +$ apt install incron +``` + +**8.2. Разрешить пользователю использоать incron** + +Для того чтобы наш пользователь мог создавать новые правила incron - нужно внести его в файл для разрешения использования incron + +```terminal +$ nano /etc/incron.allow +``` +В открывшемся редакторе отдельной строкой написать имя пользователя, например root. + +**8.3. Добавить новое правило incron** +Правило вносится в таблицу командой, после ввода которой появится редактор файла в терминале: + +```terminal +$ incrontab -e +``` + +Если на прошлом этапе вы не внесли пользователя в файл - при вводе команды вместо открытого файла получите ошибку `user 'root' is not allowed to use incron` + +Записать в открывшуюся таблицу команду + +```text +/etc/buzzer_pereodic_beep.template.conf IN_MODIFY python3 /mnt/data/root/generate_rule-buzzer_pereodic_beep.py +``` + +Команда имеет следующий формат + +```text +