Node-RED no.1 – Hello World

Node-RED je programovací nástroj, který propojuje hardwarová zařízení, API a online služby. To teda říkají jeho tvůrci, ale co to teda vlastně umí?

Instalace

Node-RED se instaluje jako NodeJS balíček nebo jako Docker obraz. Takže jej můžete nainstalovat na cokoliv kde jde NodeJs rozběhat. Já se rozhodl pro Ubuntu 18.04, které poběží pod WSL.

WSL

WSL vám umožní spustit linuxové prostředí pod Windows. Pro instalaci stačí postupovat podle návodu přímo na stránkách Microsoftu. Článek se jmenuje Windows Subsystem for Linux Installation Guide for Windows 10. Po instalaci pak už stačí otevřít terminálové okno, napsat do něj bash, potvrdit a dostanete se do prostředí Ubuntu. Po prvním spuštění je dobré provést aktualizaci a instalaci základních balíčků:

sudo apt update
sudo apt upgrade -y
sudo apt install mc build-essential -y

NodeJS

Jak už bylo zmíněno výše, pro běh Node-RED je potřeba NodeJS. Na Ubuntu se může instalace skládat ze dvou jednoduchých kroků.

curl -sL https://deb.nodesource.com/setup_11.x | sudo -E bash -
sudo apt install -y nodejs

Node-RED

Node-RED se instaluje jako globální balíček:

sudo npm install -g --unsafe-perm node-red

Po úspěšné instalaci se vypíše něco podobného jako:

+ node-red@0.20.8
added 369 packages from 352 contributors in 24.41s

V tuto chvíli je Node-RED úspěšně nainstalovat a můžete jej přes terminál spustit:

node-red

Výpis po spuštění bude vypadat následovně:

0 Sep 20:44:44 - [info]

Welcome to Node-RED
===================

10 Sep 20:44:44 - [info] Node-RED version: v0.20.8
10 Sep 20:44:44 - [info] Node.js  version: v11.15.0
10 Sep 20:44:44 - [info] Linux 4.4.0-18362-Microsoft x64 LE
10 Sep 20:44:44 - [info] Loading palette nodes
10 Sep 20:44:45 - [warn] rpi-gpio : Raspberry Pi specific node set inactive
10 Sep 20:44:45 - [warn] rpi-gpio : Cannot find Pi RPi.GPIO python library
10 Sep 20:44:46 - [info] Settings file  : /home/cpt/.node-red/settings.js
10 Sep 20:44:46 - [info] Context store  : 'default' [module=memory]
10 Sep 20:44:46 - [info] User directory : /home/cpt/.node-red
10 Sep 20:44:46 - [warn] Projects disabled : editorTheme.projects.enabled=false
10 Sep 20:44:46 - [info] Flows file     : /home/cpt/.node-red/flows_eddypc.json
10 Sep 20:44:46 - [info] Creating new flow file
10 Sep 20:44:46 - [warn]

---------------------------------------------------------------------
Your flow credentials file is encrypted using a system-generated key.

If the system-generated key is lost for any reason, your credentials
file will not be recoverable, you will have to delete it and re-enter
your credentials.

You should set your own key using the 'credentialSecret' option in
your settings file. Node-RED will then re-encrypt your credentials
file using your chosen key the next time you deploy a change.
---------------------------------------------------------------------

10 Sep 20:44:46 - [info] Server now running at http://127.0.0.1:1880/
10 Sep 20:44:46 - [info] Starting flows
10 Sep 20:44:46 - [info] Started flows

Z výpisu se mimo jiné dozvíte, kde se nacházi konfigurační soubor, ale hlavně, na jaké adrese naslouchá webové rozhraní. V našem případě se nachází na adrese http://127.0.0.1:1880/. Pokud zadáte adresu do prohlížeče, uvidíte následující:

Teorie

Node-RED není nejsložitější aplikace na ovládání, ale minimální teoretický základ je dobré znát.

Node

Základní stavební jednotkou je node (uzel). Je trochu nešikovné, že programovací jazyk, který se v Node-RED používá se jmenuje NodeJS a základní jednotka je node. Občas to působí zmatení, ale označení je logické.

Node vyobrazen jako barevný obdélník, který může mít vstupy, výstupy a plní nějakou funkci. Nody se spolu řetězí a tím vytvářejí požadovanou funkcionalitu.

Nody se dělí do několika základních skupin:

Vstupní

Vstupní nody mají za úkol přijímat data z externích zdrojů. Mohou například vytvářet HTTP endpoint, který využije aplikace v telefonu nebo vstup z Raspberry GPIO a reagovat na hodnoty připojeného čidla. Možnosti jsou obrovské, už jen proto, že momentálně existuje přes 2000 rozšiřujících balíčků pro Node-RED. Výstupní nody mají výstupní bod, kterým předávají data dále.

Výstupní

Výstupní nody leží na konci celého funkčního řetězce. Z vstupního bodu vezmou data a pošlou je do světa. Mohou vytvořit HTTP odpověď pro vaší aplikaci v telefonu, přidat položku do MQTT fronty, poslat zprávu na Telegram. Co se týče různých možností, platí to stejné co u vstupních nodů.

Funkce

Tento node se nachází někde mezi vstupním a výstupním nodem. Transformuje data získaná z vstupních bodů a pošle je dál na výstupní. Může se jednat o seřazení, vytvoření šablony, zpracování xml a mnoho dalších. Nebo si například můžete celý funkční blok napsat sami.

Flow

Napravo od výběru nodů se nachází oblast pro vytváření funkčních celků (flow). Jednoduše přetahujete myší nody zleva doprava a tažením propojujete jejich vstupy a výstupy.

Flow můžete mít více, přidávají se pomocí ikony plus napravo. Můžete vytvářet subflow. Subflow je libovolně složité flow, zabalené aby se tvářilo jako jeden node. To pomůže při složité funkcionalitě zpřehlednit flow. Jednotlivé flow jdou mezi sebou propojit pomocí nodu link.

Data

Jednotlivé nody si mezi sebou předávají data pomocí objektu msg. Msg objekt putuje od vstupního až po výstupní node. Konvencí Node-RED je, že msg objekt obsahuje proměnnou (property) payload, ve které nody očekávají data na zpracování a posílají v ní zpracovaná data dále.

const msg = {
    payload: "Data na zpracování"
}

Některé nody si mezi sebou posílají data i mimo proměnnou payload. Jedním z příkladů je HTTP endpoint. Chcete vytvořit funkcionalitu, která příjme požadavek přes vstupní HTTP node zpracuje data a odpoví klientovi. Vezmete vstupní HTTP node, nastavíte název url na kterou bude reagovat, přidáte nějaké funkční nody pro zpracování dat a nakonec výstupní HTTP node. Aby výstupní HTTP node věděl komu má odpověď poslat zpět, musí se celou dobu tato informace udržovat při průchodu objektu msg funkčními nody. Tato informace je držená v proměnné res mimo proměnnou payload, kterou se standardně předávají data na zpracování. Proto není nikdy dobré zcela destruovat a vytvářet znovu objekt msg. Mohlo by se stát, že tím požadovanou funkcionalitu rozbijete.

const msg = {
    req: {
        // objekt HTTP požadavku
    },
    res: {
        // objekt pro HTTP odpověď
    },
    payload: "Data na zpracování"
}

Kontext

Jak bylo popsáno výše, nody mezi sebou sdílí data pomocí objektu msg. To není jediný způsob jak nody mohou získat data. V Node-RED existuje mechanismus kontextu. Ten se dělí na tři části z pohledu viditelnosti.

Lokální kontext, kdy data v tomto kontextu vidí pouze node, který je do něj vložil.

Flow kontext, kdy data v tomto kontextu vidí všechny nody, které jsou propojeny s nodem, který je do tohoto kontextu vložil. Ať přímo či nepřímo.

Globální kontext, kdy data v tomto kontextu vidí všechny nody.

Těchto kontextů lze využít pro sdílení dat mezi nody. I když pokud použijeme flow kontext, tak by asi čistější řešení bylo předávání potřebných dat pomocí objektu msg. Větší smysl dává globální kontext. Ten se například použije v případě kdy do Node-RED importujeme nějakou externí NodeJS knihovnu, kterou potřebujeme. Vložíme ji do globálního kontextu a každý node s ní bude moct pracovat. V tomto případě, kdy importujeme externí NodeJS knihovnu ji je možno použít při psaní vlastních funkcí.

// zavolání knihovny z globálního kontextu
const _ = global.get('lodash')

Hello World

Jako příklad si zkusím vytvořit jednoduchou funkcionalitu. Řekněme, že chceme z webu novin stahovat perexy zpráv. Na idnes.cz má krátký popisek zpráv na hlavní stránce přiřazenou CSS třídu .perex. Pro stažení stránky můžeme použít funkci http request.

Přetáhneme ji do flow a dvojklikem otevřeme nastavení. Je potřeba nastavit položku Method na GET, do URL zadat https://www.idnes.cz a do Name jméno nodu (to není povinné).

Jako další použijeme funkci html.

Ta když dostane na vstupu html, tak dokáže filtrovat data na základě css identifikátorů. Nastavím Selector na .perex.

Předposledním nodem, který použijeme, je debug. Ten nám umožní vypisovat informace do ladící konzole.

Jako poslední přidáme node inject.

Aby celý řetězec nodů fungoval potřebujeme vyvolat jeho spuštění. Funkce http request není vstupní node, takže potřebujeme něco co jej aktivuje. V tomto případě to zařídí node inject, který umožňuje ruční spuštění.

Pak už stačí pouze nody propojit.

Před samotným spuštěním musíme ještě zpropagovat nové změny. To se provede pomocí tlačítka Deploy vpravo nahoře. V pravém horním rohu klikneme na ikonu brouka abychom si zobrazili debug výstup a pomocí tlačítka u vstupního nodu (ten s tou šipkou) provedeme spuštění. V debug výstupu by se mělo objevit následující:

Řešení je funkční, ale brzy narazíme na problém. Seznam.cz používá pro perex CSS třídu .article__perex, takže můžeme zkusit předělat příklad pro Seznam.cz.

Pokud takto upravený flow spustíte, dostanete v debug konzoli následující:

Ano, nic! Příčinu není úplně jednoduché najít. Node-RED je primárně dělaný pro IOT, proto je jeho http request modul jednoduchý. Neumí si poradit s přesměrováním (HTTP 301) nebo s kompresí. A to není úplně chyba, protože nějaká bezdrátová kamerka v lokální siti s http rozhraním nepotřebuje komprimovat odpověď. Ale seznam.cz posílá odpovědi komprimované a http request sice proběhne správně, ale předá nodu html změť dat se kterou si neporadí. Ten očekává html kód.

Existuje vícero možností jak to vyřešit. Najít modul, který to zvládne a nebo si napsat funkci vlastní. My si tady vyzkoušíme napsat funkci vlastní. NodeJS existuje dobrá knihovna na provádění HTTP dotazů, axios. Tu potřebujeme nějakým způsobem dostat do Node-RED.

Po instalaci vytvořil Node-RED v domovském adresáři složku .node-red, která je normální NodeJS projekt. Pomocí nástroje npm nainstalujeme ve složce .node-red knihovnu axios.

cd ~/.node-red
npm i axios

Následně musíme dát Node-RED vědět, že je knihovna dostupná. Ve složce .node-red se nachází soubor settings.js, ten je potřeba upravit tak, že přidáme axios do globálního kontextu. Do functionGlobalContext je nutné přidat axios:require(‘axios’).

functionGlobalContext: {
    axios:require('axios')
    // os:require('os'),
    // jfive:require("johnny-five"),
    // j5board:require("johnny-five").Board({repl:false})
},

Jakmile máme přidáno je nutné restartovat Node-RED. Přidáme funkci function a vložíme do ní následující kód.

const axios = global.get('axios')

;(async function () {
    const data = await axios.get(msg.payload, {
        maxRedirects: 5,
    })

    node.send({ payload: data.data })
})()

return

Na prvním řádku voláme z globálního kontextu knihovnu axios. Na třetím řádku vytváříme asynchronní obalovací funkci abychom mohli použit await. V NodeJS 11, který jsme instalovali ještě nejde použít await mimo asynchronní funkci. Na řádku čtyři použijeme metodu get z naimportované knihovny axios. První parametr je msg.payload, který přijde na vstupu do nodu a očekáváme v něm URL. Druhý parametr je objekt nastavující GET dotaz. Pokud nás požadovaná URL přesměruje, bude axios toto přesměrování následovat. Maximální hloubka je 5. Na řádku osm předáváme data na výstup pomocí node.send metody. Tato metoda se volá v případě, že vracíme data z asynchronní funkce. V opačném případě se pro návratovou hodnotu používá standardně return. V Node-RED to bude vypadat následovně.

Funkce je hotová. Očekává vstup v msg.payload. Ten zařídíme tak, že upravíme inject node, tak aby v msg.payload posílal URL adresu.

Axios za nás vyřeší kompresi i přesměrování a když nové flow zpropagujeme a spustíme, tak na debug výstupu dostaneme něco takového.

Debug výstup je super, ušetří hodně času, ale jinak nic moc. V Node-RED si můžete vytvořit dashboard který vám bude zobrazovat informace. Je potřeba doinstalovat modul. Vpravo nahoře rozklikněte hamburger menu a zvolte Settings. Pak možnost Palette a v ní tab Install. Do vyhledávaní vepište dash a následně nainstaluje pomocí tlačítka install modul node-red-dashboard.

Po úspěšné instalaci vám napravo vznikne celá nová sekce dashboard.

Pro zobrazení na dashboardu použijeme node template ze sekce dashboard.

Vložíme ho do flow a napojíme na jeho vstup výstup html nodu.

Po rozkliknutí nodu template na nás bude červeně svítit, že musíme přidat novou UI skupinu. Pomoc tužky napravo od položky Group skupinu vytvoříme a přiřadíme.

Po kliknutí na tužku se zobrazí další nabídka, kde je potřeba prvně přidat nový UI tab. Opět klikneme na tužku.

V posledním zanoření potvrdíme přednastavené hodnoty pomocí tlačítka Add.

A proklikejte se pomocí tlačítka Add zpět do nejvyšší úrovně na začátek.

A potvrďte pomocí Done. Po zpropagování a ověření, že vše funguje můžete zkusit zadat do nového tabu prohlížeče adresu http://127.0.0.1:1880/ui. Měl by se tam nacházet dashboard.

Přidaný node template zatím nic moc nevypsal. Znovu node template editujte a přidejte následující kód.

<div>
<div style="padding-bottom: 10px; border-bottom: 1px solid #333" ng-repeat="item in msg.payload">
        <div>{{item}}</div>
</div>
</div>

Šablona očekává pole hodnot, které vepíše pomocí divů.

Uložte, zpropagujte a spusťte a pak se podívejte znovu do dashboardu. Měli byste vidět něco podobného.

Takto si můžete jednoduše vytvořit přehledný dashboard, který vám bude na jednom místě ukazovat všechny zásadní údaje z vašich flow. To už na hello world příklad asi stačí.

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *