UBOS Community

vova
vova

Posted on • Updated on

Вузол 'function' в Node-RED

Вузол function дозволяє запускати JavaScript код для повідомлень, які через нього передаються. Повідомлення передається як об'єкт під назвою msg. За замовчуванням він матиме msg.payload властивість, що містить тіло повідомлення.
Інші вузли можуть додавати власні властивості до повідомлення. Вони повинні бути описані в їхній документації.

Написання функцій

Код який введений у вузол function, представляє тіло функції. Найпростіша функція повертає повідомлення таким яким воно є.

return msg;
Enter fullscreen mode Exit fullscreen mode

Якщо функція повертає null, повідомлення не передається, і потік завершує свою роботу.
Функція завжди повинна повертати об'єкт msg. Повернення числа або рядка призведе до помилки.
Повернений об'єкт повідомлення не обов'язково має бути таким же об'єктом, як передано. Функція може побудувати новий об'єкт перед тим як повернути його. Наприклад:
Image description

Примітка: створення нового об’єкта повідомлення призведе до втрати будь-яких властивостей повідомлення отриманого повідомлення. Це порушить деякі потоки, наприклад, потік HTTP In/Response вимагає обов'язкового збереження властивостей msg.req і msg.res. Загалом, функціональні вузли повинні повертати об’єкт повідомлення, який вони передали після внесення будь-яких змін до його властивостей.

Приклад як потрібно робити

Створимо потік який повертає значення body, який ми передаємо у запиті. Використаємо вузли http in та http response (детальніше про них тут).
Image description Вузол http in відправляє у function повідомлення з властивостями payload, req, res. У тілі функції нам потрібно тільки записати у msg.payload потрібно нам значення не заміняючи весь об'єкт msg. Тоді вузол http response зрозуміє, що йому потрібно повернути відповіді від нашого запиту.
Зробимо запит за допомогою Postman.
Image description У відповідь отримали текст який передавали у body.

Приклад як не потрібно робити

Давайте зміним тіло функції вище описаного потоку на:
Image description У консолі отримає повідомлення "No response object". Через те, що ми створили новий об'єкт повідомлення, вузол http response не знає, що йому потрібно повертати.
Тому якщо потрібно створити нові властивості їх потрібно записувати у msg не створюючи новий.

Декілька виходів

У діалоговому вікні функції є можливість змінити кількість виходів та назву функції.
Image description Додамо два виходи і зміним назву функції.
Image description Тепер у вузла function є два виходи. Далі постає питання. А як їх контролювати? Потрібно використовувати оператор if та у його тілі повертати масив повідомлень. Кількість повідомлень у масиві залежить від кількості виходів які нумеруються від верху до низу.

if (msg.payload.length > 0) {
    msg.payload = `array length: ${msg.payload.length}`;

    return [ null, msg ]
}

msg.payload = "Empty"
return msg;
Enter fullscreen mode Exit fullscreen mode

Для прикладу у нас є два виходи return [ null, msg ]. У перший вихід повертаємо null це означає, що функція у цьому випадку нічого не повертає на перший вихід. У другий вихід передаємо msg. Тому якщо у функцію прийде масив з декількох елементів, то у другий вихід повернеться рядок довжини масиву. В противному випадку повертаєм return msg у перший виході.
Image description Додамо ще одну функцію data яка повертає масив об'єктів.

msg.payload = [
    { name: "banana" },
    { name: "potato" }
];

return msg;
Enter fullscreen mode Exit fullscreen mode

Image description Умова повернула true тому повідомлення відправилось на другий вихід. Якщо у функцію data записати пустий масив, то умова не виконається і повідомлення відправиться на перший вихід.

msg.payload = [];
return msg;
Enter fullscreen mode Exit fullscreen mode

Image description

Реєстрація подій

Для того щоб ефективно проводити debug коду, треба розуміти які дані приходять та змінюються. Для цього потрібно використовувати наступні функції які будуть записувати в консоль повідомлення (аналог console.log() в JavaScript).

node.warn("Something happened");
node.error("Something bad happened");
Enter fullscreen mode Exit fullscreen mode

Змінимо приклад який ми розглядали вище. Додамо цикл який перебирає масив і виводить його елементи у консоль.

if (msg.payload.length > 0) {
    node.warn("start if");

    for (const element of msg.payload) {
        node.warn(element);
    }

    return [ null, msg ]
}

msg.payload = "Empty"
return msg;
Enter fullscreen mode Exit fullscreen mode

Image description У консолі можна побачити 3 події node.warn.

Обробка помилок

Якщо функція знаходить помилку і потрібно завершити виконання потоку то вона не повинна нічого повертати. Щоб викликати Catch у певному вузлі функція повинна викликати node.error("error", msg) передаючи у перший аргумент текст помилки, а у другий msg.

Змінимо попередній приклад додавши у функцію data помилку

msg.payload = [
    { name: "banana" },
    { name: "potato" }
];

node.error("Еrror", msg);
Enter fullscreen mode Exit fullscreen mode

Image description Функція data повернула помилку тому вузол зупинив роботу

Manage palette

Для того, щоб додати додаткові node-red вузли у проект потрібно відкрити меню справа та вибрати вкладку Manage Pallete.
Image description У вкладці Nodes зберігаються бібліотеки які вже завантаженні, а у вкладці Install потрібно ввести назву бібліотеки та завантажити її.

Перед завантаженням бібліотеки варто ознайомитись з її документацією

Image description Після завантаження у списку всіх вузлів з'являться нові завантажені вузли
Image description

NPM package

NODE-Red дозволяє витягувати додаткові модулі з Node Package Manager. Для цього потрібно вибрати вузол function у який нам потрібно використати додатковий модуль та перейти у вкладку Setup. У цій вкладці натиснути кнопку add та ввести модуль який потрібно використовувати. Якщо такий модуль існує на платформі NPM, то ми зможемо його використовувати.
Створимо потік який приймає зображення яке ми оптимізовуємо та перевертаємо.
Image description Використаєм новий вузол viewer який раніше ми завантажували.

Зверніть увагу! Для роботи з зображеннями варто використовувати метод POST та дозволити завантаження зображення

Image description
Додамо модуль sharp для роботи з зображеннями.
Image description У тіло функції додаємо логіку роботи з зображенням.

const optimized = await sharp(msg.req.files[0].buffer)
    .toFormat("jpeg", { quality: 60 })
    .flip()
    .toBuffer();

msg.payload = optimized;

return msg;
Enter fullscreen mode Exit fullscreen mode

Через Postman відправимо зображенням. Тіло запиту буде типу form-data. Для зображення потрібно вибрати тип file.
Image description Результат виконання
Image description
Запит відправляє буфер зображення який зберігається за таким шляхом msg.req.files[0].buffer. Відправлене зображення важить size: 414164(404 КБ)
Image description Конвертоване зображення 292563 (285 КБ)
Image description

Discussion (0)