Добавить свои пути в /etc/default/wb-rules нет такого файла

Добрый день в Wiki сказано -

Добавить свои пути можно редактированием /etc/default/wb-rules добавлением путей к переменной WB_RULES_MODULES через разделитель : :

но у меня нет такого файла или пути в

/etc/default/wb-rules

Скриншот прилагаю или его нужно создавать самому или не там смотрю?
Wiren Board 7.3.4 прошивка тестовая 5.10.35-wb169 unstable latest

Все верно, /etc/default/wb-rules надо создать, изначально его нет.

Что он может содержать? каков формат? можно пример? Ну и не плохо было бы тогда WIKI поправить, а то я на сайте пытался искать по ключевому слову и пути и ничего не нашёл похожего. И еще, по этому новому пути если его добавить можно класть только скрипты или модули тоже? Или перефразирую можно ли указать свою папку для модулей?

Добрый день, прошу уточнить задачу которую вы пытаетесь реализовать созданием пути?

Всего лишь структуризация скриптов и модулей.
Допустим модули для обслуживания значений давлений, расходов по одному пути / xxx/xxxx/ Pressure 1…n/
температуры по другому / xxx/xxxx/ Temperature 1 … n/
скрипты (которые не модули) по другому /ххх//ххх/Calculate/ и т.д

Понятно что можно сделать все по одному пути в разных файлах или вообще все в одном но это не совсем удобно на мой взгляд.

И еще вопрос можно ли у виртуального устройства копировать поведение как у реального при возникновении ошибок связи?. (Покраснение в интерфейсе) если у устройства которое используется в данном VirtualDevice произошла потеря связи или ошибка (признак r в mete) а еще лучше копировать это поведение от реального в виртуального если мы его используем. Поясню нередко мы создаем виртуальное устройство чтобы сделать некий пересчет значений (калибровку) или логику основываясь на подписку реального устройства. Если устройство по каким то причинам перестало отвечать в виджете VD я не увижу изменений (Визуальных) . Да я могу подписаться через track и сделать необходимые действия но это не то

Добрый день!

Папки для скриптов, если вам требуется, создаются через базовую команду mkdir. Централизация хранения различных скриптов, на мой взгляд, более удобна в плане их нахождения. Главное — называть их понятно, а путь не так важен.

По поводу копирования поведения не скажу, но можно отдельно выводить строкой состояние точно.
Примерный сценарий статуса

1 Like

Спасибо за mkdir. Папки создать не проблема, сейчас для вывода делаю так

// Функция создания правила подписки на пропадании связи с устройствами 
function checkSerialDevices (){
    try {
       return trackMqtt("/devices/+/controls/+/meta/error", function(message){
            log.info("name: {}, value: {}".format(message.topic, message.value))
            if (message.value == "r"){
                dev[nControl_FID + sErrorTXT] = "Нет связи с " + message.topic;                 // Выводим подсказку  в WEB UI
                dev[nControl_FID + sWarningTXT] = " Значение ошибки " + message.value;          // Выводим подсказку  в WEB UI
                log.error ("Устройство {} вернуло код ошибки {}", message.topic, message.value);
                dev[nControl_FID + sStateFID] = 404;                                            // Устанавливаем флаг перехода шаг 404 (аварийное состояние) 
            };  
        });
          
    } catch (error) {
        dev[nControl_FID + sErrorTXT] = " Try checkSerialDevices " + error;
        log.error("Try checkSerialDevices =" + error);
        dev[nControl_FID + sStateFID] = 404;
        return null;  
    };
};

Error WB UI

а хотелось бы
Err real
Err real2

Но при большом количестве виджетов или если в виджете много строк визуально не везде это увидишь. Вывод пока не форматировал (есть наползание ). Ну и по первому вопросу в пути WB_RULES_MODULES что вписывать? просто добавить свой путь от корневого и все? системные не надо? или системные не зависят от него и он распространяется только на пользовательские? пример дадите?

Переписал функции подписки и создания виртуального устройства пока так

Спойлер
// Скрипт подписывается на топики ошибок связи и выводит в UI информацию о ошибках
var Device      = "Check_serial_error";
var NameEN      = "Check serial error";
var NameRU      = "Обработка ошибок связи"
var nDevice     = Device;
var sErrorTXT   = "/Error_TXT";
var sWarningTXT = "/Warning_TXT";
var sResetError = "/pbReset";

//----------------СОЗДАНИЕ ВИРТУАЛЬНОГО УСТРОЙСТВА----------------------//
// Функция создание виртуального устройства 
function Create_VDevice(vdDevice,vdNameEN,vdNameRU) {
    try {
        return defineVirtualDevice(vdDevice, {
            // имя виджета в GUI
            title: { en: vdNameEN, ru: vdNameRU},
            cells: {
                // Текущая ошибка WEB UI
                Error_TXT: {
                    title: { en: "Current Error", ru: "Текущая ошибка" },
                    type: "text",
                    value: "Отсутствует",
                    readonly: true,
                    forceDefault: true,
                    order: 1,
                },
                  // Текущая предупреждение WEB UI
                Warning_TXT: {
                    title: { en: "Current warning", ru: "Предупреждение" },
                    type: "text",
                    value: "Отсутствует",
                    readonly: true,
                    forceDefault: true,
                    order: 2,
                },
                // Кнопка сброса ошибки.
                pbReset: {
                    title: { en: "Reset error", ru: "Сброс ошибки" },
                    type: "pushbutton",
                    value: "false",
                    forceDefault: true,
                    order: 3,
                },
            },
        });
    } catch (error) {
        log.error("try Error Create " + NameVD + "  =" + error);
        return undefined;
    };
};

// Функция подписки на изменение топика кнопки "СБРОС ОШИБКИ" в WEB UI
function RuleResetError(RuleName) {
    try {
        return defineRule(RuleName, {
            whenChanged: Device + sResetError,                    // подписка на событие нажатия на кнопку "Сброс ошибки" в WEB UI
            then: function (newValue, devName, cellName) {        // devName = Control cellName = pbResetFID
                log("Произведен ручной сброс ошибки");            // логирование в консоли
                //ResetCurrentError();                            // Вызываем функцию сброса ошибок
                dev[Device + sWarningTXT] = "Отсутствует";        // Очищаем поле предупреждений
                dev[nDevice + sErrorTXT] = "Отсутствует";         // Выводим подсказку  в WEB UI
            },
        });
    } catch (error) {
        log.error("try Error RuleResetError: '" + error + "'");
        return undefined;
    };
};

//----------------ФУНКЦИИ СОЗДАНИЯ ПОДПИСОК НА ТОПИКИ MQTT----------------------//
// Функция создания правила подписки на пропадании связи с устройствами 
function CheckSerialDevices (){
    try {
        // Подписка на все устройства в которых есть топики /meta/error"
        return trackMqtt("/devices/+/controls/+/meta/error", function(message){     // Подписка на все устройства в которых есть топики /meta/error"
        // log.info("name: {}, value: {}".format(message.topic, message.value))
            
            // Функция извлечения текста в виде "устройство/топик"
            function GetDeviceName(string) {
                var parts = string.split('/');                                      // Разделяем строку по символу '/'
                return parts[2] + '/' + parts[4];                                   // Извлекаем нужные части и объединяем их
            };

            // Преобразовываем полученное значение для дальнейшего использования
            var ShortDeviceString = GetDeviceName(message.topic); 

            // В зависимости от полученного значения ошибки (message.value) выполняем различные действия  
            switch (message.value) {

                // Если текущая ошибка равна "r" нет ответа от устройства то
                case "r":
                    dev[nDevice + sErrorTXT] = "Ошибка чтения из устройства";  // Выводим подсказку  в WEB UI
                    dev[nDevice + sWarningTXT] = ShortDeviceString;            // Выводим подсказку  в WEB UI
                    log.error(
                        "Ошибка чтения из устройства:  {}",
                        ShortDeviceString
                    );
                    break;
                    
                // Если текущая ошибка равна "w" запись в устройство не удалась 
                case "w":
                    dev[nDevice + sErrorTXT] = "Ошибка записи в устройство";   // Выводим подсказку  в WEB UI
                    dev[nDevice + sWarningTXT] = ShortDeviceString;            // Выводим подсказку  в WEB UI
                    log.error(
                        "Ошибка записи в устройств  {}",
                        ShortDeviceString
                    );
                    break;

                // Если текущая ошибка равна "rp" попытка возобновить чтение после таймаута не удалась 
                case "rp":
                    dev[nDevice + sErrorTXT] = "Ошибка возобновления чтения";  // Выводим подсказку  в WEB UI
                    dev[nDevice + sWarningTXT] = ShortDeviceString;            // Выводим подсказку  в WEB UI
                    log.error(                                                 // Выводим в лог
                        "Попытка возобновить чтение с устройства:  {} не удалась",
                        ShortDeviceString
                    );
                    break;

                // Если текущая ошибка равна "wp". Прим. (сюда не разу не попал наверно такого не бывает)      
                case "wp":
                    log.warning(
                        "Попытка возобновить запись в устройство?:  {}, ",        // Выводим в лог
                        ShortDeviceString
                    );
                break;

                // Если текущая ошибка равна (p)периодическая попытка чтения? 
                case "p":
                    dev[nDevice + sErrorTXT] = "Ошибка возобновления";         // Выводим подсказку  в WEB UI
                    dev[nDevice + sWarningTXT] = ShortDeviceString;            // Выводим подсказку  в WEB UI
                    log.error(                                                 // Выводим в лог
                        "Попытка возобновить чтение с устройства:  {} не удалась",
                        ShortDeviceString
                    );
                    break;

                // Насколько понял сюда попадем в случае возобновления связи с устройством (чтение или запись которые раньше не читались или не записывались)
                default:
                    dev[nDevice + sErrorTXT] = "Связь восстановлена";          // Выводим подсказку  в WEB UI
                    dev[nDevice + sWarningTXT] = ShortDeviceString;            // Выводим подсказку  в WEB UI
                    log.warning(
                        "Возобновление связи c устройством:  {}, код: ({})",      // Выводим в лог
                        ShortDeviceString, message.value
                    );
                    break;
            };
      });
    // При исключении выводим в MQTT и лог значение которое привело  к этому        
    } catch (error) {
        dev[nDevice + sErrorTXT] = " Try checkSerialDevices: " + error;
        log.error("Try checkSerialDevices: " + error);
        return null;  
    };
};
//----------------НЕПОСРЕДСТВЕННОЕ СОЗДАНИЕ ----------------------//
var vdCreateCheckSerialError = Create_VDevice (Device,NameEN,NameRU);
var ChangedCheck = CheckSerialDevices ();
var ChangedButton = RuleResetError ("RuleResetError");

вложение
TEST.zip (2,4 КБ)

в интерфейсе это выглядиn так
Serial err1

в логе
Err Serial2 log

при восстановлении
Serial warningPNG
Прим. Сохраняем последнюю ошибку в предупреждении.(после перенесу в журнал ошибок)

в логе так
Serial log warning

да конечно можно сделать еще алармом, но все равно не так будет. У реального устройства видна в том числе попытка реанимировать связь (появляется еще значок)
Err real2

Искал долго информацию что может быть в meta/error? нашел в https://github.com/wirenboard/conventions/blob/main/README.md#errors, где на мой взгляд не очень понятно написано topics can contain a combination of values в переводе и их вариации ???, какие??? .Можете перечислить? это же не трудно. Как именно я понял все возможные комбинации см. под спойлер или вложение. Даже пример в Wiki на который здесь ссылались отслеживает только чтение, а если есть и критичная запись в устройство? например (отключить реле). Почему сразу не привести пример на все возможные комбинации?
И не понятно почему это не описать и в https://github.com/wirenboard/wb-mqtt-serial раз оно более всего к нему относится например в главе Обработка ошибок связи и/или где то здесь https://github.com/wirenboard/wb-rules?tab=readme-ov-file#%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF-%D0%BA-%D1%82%D0%BE%D0%BF%D0%B8%D0%BA%D0%B0%D0%BC-meta
Но это так, лирическое отступления пока жду ответ на предыдущие вопросы. В любом случае спасибо Вам за поддержку!
P.S. Причина редактирования ошибки отображения и изменение кода примера

Добрый день!

Благодарю за столь расширенный ответ. Скрипт обязательно возьму на вооружение.

Могу ли я еще чем-то помочь?