Node-RED, lavkode og flytbasert programmering for IoT
Posted on 12/08/2024 by Øivind Heggland
Node-RED er et grafisk program verktøy for å koble sammen maskinvare, APIer og andre online tjenester ved å legge inn noder og koble dem sammen ved hjelp av linjer.
Lav kode utvikling.
Node-RED
Når oppstod Node-RED og hva var årsaken.
Node-RED ble opprinnelig startet som et sideprosjekt av Nick O’Leary og Dave Conway-Jones mens de jobbet i IBM’s Emerging Technology Services Group i begynnelsen av 2013. Det begynte som et “proof-of-concept” for å kunne visualisere og manipulere koblinger mellom MQTT-emner. De innså raskt at dette konseptet kunne utvides til å være mer generelt og kunne fungere for mer enn bare MQTT.
I september 2013 ble Node-RED gjort til et åpen kildekode-prosjekt. I oktober 2016 ble det et av de første grunnleggende prosjektene til JS Foundation. Denne stiftelsen ble senere i 2019 omdøpt til OpenJS Foundation. Siden den gang har Node-RED fortsatt å vokse og utvikle seg, og er nå et populært verktøy for å koble sammen maskinvareenheter, APIer og nettjenester på nye og interessante måter.
Hvorfor heter det Node-RED
Kort fortalt var det fordi det var et ordspill på “Code Red” , Node ble brukt fordi det passet med måten man programmerte og at det baserte seg på Node.Js i bunn. RED delen har de egentlig aldri funnet ut av hva står for, de tenkte Rapid Event Developer, men har aldri blitt definert.
Utvikling av Node-RED
Den første utgivelsen av Node-RED, versjon 0.2.0, ble gjort tilgjengelig på GitHub den 16. oktober 2013. Siden den gang har det vært jevnlige oppdateringer. Da jeg begynte å bruke Node-RED i 2019, var den første versjonen jeg jobbet med 0.18.7, som ble utgitt 25. mai 2018.
Den 6. september 2019 ble versjon 0.20.8 lansert, og senere samme måned, den 30. september 2019, ble versjon 1.0.0 av Node-RED lansert. Med denne utgivelsen kunne Node-RED endelig betraktes som klar for produksjon. Før lanseringen av versjon 1.0.0 var det tilfeller hvor ikke alt fungerte som det skulle.
Siden lanseringen av versjon 1.0.0 og frem til i dag, med den nåværende versjonen 3.1.6, har Node-RED i stor grad forblitt det samme. Det har vært noen forbedringer og nye funksjoner, men kjernefunksjonaliteten har ikke endret seg. Derfor spiller det ikke en stor rolle om man kjører versjon 1 eller 3 i dag.
De største endringene fra versjon 1 til 3 har handlet om Node.js og når det blir “end of life”. Versjon 4 av Node-RED vil i hovedsak komme for å tydeliggjøre endringer i Node.js-versjonen.
Samfunnsdreven
En av styrkene til Node-RED er at det er Åpen kildekode og at mye av arbeidet kommer fra samfunnet. Dette har gitt starten av prosjektet fra V0.2 og opp til V3.1.6 en god boost i stabilitet, funksjonalitet og andre bugfikser. Utviklingen av Node-RED har gått jevnlig frem til 18. Februar 2022, når versjon 2.2.2 ble lansert. Etter det så har nylanseringer tatt lengre tid. Det er flere årsaker til dette , det er ikke mangel på ønsker, forslag og bidrag, men det har med flere faktorer som Modenheten av Node-RED gjør at endringer og ny funksjonalitet er mer kompleks enn før. Samtidig så selv om koden er lett tilgjengelig, så er det gatet av de som eier Node-RED og passer på at ny funksjonalitet er gjennomtenkt og passer inn i det større bildet.
https://github.com/Node-RED/Node-RED/graphs/code-frequency
Node-RED github-koden har pt 219 bidragsytere til prosjektet. Hvor 10 av dem er en del av Node-RED organisasjonen på Github. Som ikke bare gjelder Node-RED selv men også en del andre noder og kode
Node-RED Github Organisasjon
I tillegg til at Node-RED er mer moden og funksjon komplett, så er en av hovedårsakene til at utviklingen har roet litt ned at teamet har flyttet fokus fra Node-RED og mer over på hvordan Node-RED kan brukes i bedrifts sammenheng og dermed startet FlowFuse og jobber mer fokusert på det, rammen rundt Node-RED.
Hva er Node-RED og hva gjør det
Node-RED er et programmeringsverktøy for å koble sammen maskinvareenheter, APIer og nettjenester på nye og interessante måter. Det består av to hovedkomponenter:
Runtime: Kjernen i Node-RED er basert på Node.js, som driver koden du lager. Alt er skrevet i JavaScript.
Editor: Dette er også skrevet i JavaScript og gir brukeren muligheten til å programmere ved hjelp av en webbasert editor.
Node-RED bruker en metode kalt “flow-basert programmering”, oppfunnet av J. Paul Morrison på 1970-tallet. I denne webbaserte editoren drar du inn de nodene du ønsker å jobbe med, kobler dem sammen på den måten du trenger, og konfigurerer nodene med de parametrene og funksjonaliteten du trenger.
Node-RED har et sett med noder ferdig installert med kjernefunksjonalitet. Du kan utvide det med noder som er laget av samfunnet, og som en siste løsning kan du trekke inn funksjonsnoder som gir brukeren muligheten til å skrive ren JavaScript-kode, med de fordeler og ulemper det har.
Introduction – Node-RED Essentials
Utvikling:
Node-RED er fleksibelt, det kan installeres lokalt på din pc, kjøres i docker og kubernetes, raspebrry pi , til og med Microkontrollere.
Hva kan det brukes til
Gjennom årene har bruken av Node-RED vokst, spesielt innenfor IoT og Industri 4.0. Dette skyldes hovedsakelig dens evne til å kommunisere og hente data fra proprietære løsninger som ikke er koblet til nettet. Node-RED er utmerket for visualisering av data fra for eksempel PLCer, og for å gjøre denne dataen tilgjengelig på internett eller sende den videre til en database.
Node-RED er også en enkel måte å sy sammen data fra flere kilder ved hjelp av noder. Den passer svært godt innenfor IoT, med støtte for protokoller som HTTP, MQTT, Modbus, OPC UA og SQL, noe som gir mange muligheter for tilkobling.
I eksisterende bedrifter er det ofte mange komponenter som ikke er egnede eller har tradisjon for å være lett tilgjengelige for brukere. Node-RED kan være bindeleddet som gir brukere lettere tilgang til komponentene, enten i form av mer brukervennlig styring eller dashbord, eller for å samle generert data på et mer sentralt sted for senere bruk, for eksempel til maskinlæring.
Det finnes mange eksempler på hvordan Node-RED kan brukes. Det kan fungere som et alternativ til POSTMAN, og det er enkelt å lage prototyper av funksjonalitet med det.
Hvor kan det brukes.
Personlig har jeg brukt Node-RED til styring av smarthus, og mer spesifikt som hjernen i mitt eget smarthus. Jeg bruker i hovedsak kun Node-RED, men Smarthus-huber som Home Assistant har en Node-RED-plugin som kan installeres med tilhørende noder, dette gjøre det mulig å utvide funksjonalitet i Home Assistant uten å måtte bygge alt fra bunn av.
Blant annet fikk jeg nylig til hente ut data fra hentavfall.no for min adresse i Sandnes, for å kunne se hvilke avfall som skal hentes og hvilken dag. Jeg fikk laget en enkel flow som henter ut bildet av avfallet som skal tømmes.
Nodene som er installert i tillegg til standard er :
- node-red-contrib-cheerio-function
- @flowfuse/node-red-dashboard
Node-RED flow
[
{
"id": "19a61e2a.75f152",
"type": "tab",
"label": "Tømmekalender",
"disabled": false,
"info": ""
},
{
"id": "7268b8b9.eb7ae",
"type": "inject",
"z": "19a61e2a.75f152",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "00 12 * * *",
"once": false,
"onceDelay": "5",
"topic": "",
"payload": "",
"payloadType": "date",
"x": 190,
"y": 320,
"wires": [
[
"c70310c4.a7eb78"
]
]
},
{
"id": "c70310c4.a7eb78",
"type": "http request",
"z": "19a61e2a.75f152",
"name": "",
"method": "GET",
"ret": "txt",
"paytoqs": "ignore",
"url": "https://www.hentavfall.no/rogaland/sandnes/tommekalender/show?id=759fbf09-3f7f-4c41-aa70-54d3902d915f&municipality=Sandnes%20kommune%202020&gnumber=38&bnumber=1696&snumber=4",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 370,
"y": 320,
"wires": [
[
"5c9d5ab90b9643f7"
]
]
},
{
"id": "5c9d5ab90b9643f7",
"type": "cheerio-function",
"z": "19a61e2a.75f152",
"name": "",
"func": "\nconst items = $('.waste-calendar__item'); // Select all elements with class 'waste-calendar__item'\n\nconst extractedData = items.map((index, element) => {\n const date = $(element).find('td:first-child').text().trim(); // Extract the date\n const images = $(element).find('img.waste-container-icon[src]').map((i, img) => $(img).attr('src')).get(); // Extract image URLs\n return { date, images };\n}).get();\n\n\nmsg.payload = extractedData\nreturn msg;",
"outputs": 1,
"noerr": 10,
"x": 380,
"y": 380,
"wires": [
[
"d5631660e7e2357e",
"3060dfc94ade0f86"
]
]
},
{
"id": "8e57f94726f5be98",
"type": "debug",
"z": "19a61e2a.75f152",
"name": "Dato -Dag",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 810,
"y": 360,
"wires": []
},
{
"id": "8d6b27c1c9e2c2e0",
"type": "split",
"z": "19a61e2a.75f152",
"name": "For hver Avfallstype",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "",
"x": 590,
"y": 460,
"wires": [
[
"b18db77dc706d617",
"c42c0fc74c149b91"
]
]
},
{
"id": "d5631660e7e2357e",
"type": "change",
"z": "19a61e2a.75f152",
"name": "Avfallstype Bilder",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "payload[1].images",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 590,
"y": 420,
"wires": [
[
"8d6b27c1c9e2c2e0"
]
]
},
{
"id": "b18db77dc706d617",
"type": "debug",
"z": "19a61e2a.75f152",
"name": "Avfallstyper",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 810,
"y": 460,
"wires": []
},
{
"id": "3060dfc94ade0f86",
"type": "change",
"z": "19a61e2a.75f152",
"name": "Dato - Dag",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "payload[1].date",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 570,
"y": 360,
"wires": [
[
"8e57f94726f5be98"
]
]
},
{
"id": "307b1fd4d57c05fc",
"type": "ui-template",
"z": "19a61e2a.75f152",
"group": "e63aca3c0dabe7de",
"page": "",
"ui": "",
"name": "Vis Avfallstyper for neste Tømming",
"order": 0,
"width": 0,
"height": 0,
"head": "",
"format": " <template v-slot:item=\"\">\n<div class=\"col-lg-2\" v-for=\"pic in msg?.payload\">\n <img style=\"height: 100px;\" v-bind:src=\"pic\" v-bind:alt=\"pic\">\n</div>\n </template>",
"storeOutMessages": true,
"passthru": true,
"resendOnRefresh": true,
"templateScope": "local",
"className": "",
"x": 1100,
"y": 540,
"wires": [
[]
]
},
{
"id": "c42c0fc74c149b91",
"type": "change",
"z": "19a61e2a.75f152",
"name": "Generer Bilde Adresse",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "\"https://www.hentavfall.no/\"&payload",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 800,
"y": 500,
"wires": [
[
"d0cfa1719585871c"
]
]
},
{
"id": "d0cfa1719585871c",
"type": "join",
"z": "19a61e2a.75f152",
"name": "Kombiner Avfallstyper",
"mode": "auto",
"build": "object",
"property": "payload",
"propertyType": "msg",
"key": "topic",
"joiner": "\\n",
"joinerType": "str",
"accumulate": true,
"timeout": "",
"count": "",
"reduceRight": false,
"reduceExp": "",
"reduceInit": "",
"reduceInitType": "",
"reduceFixup": "",
"x": 800,
"y": 540,
"wires": [
[
"307b1fd4d57c05fc",
"f488905696dd9bb9"
]
]
},
{
"id": "f488905696dd9bb9",
"type": "debug",
"z": "19a61e2a.75f152",
"name": "Kombinerte linker",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 1050,
"y": 500,
"wires": []
},
{
"id": "e63aca3c0dabe7de",
"type": "ui-group",
"name": "SøppelTømming",
"page": "e8ae1befc87a269b",
"width": "6",
"height": "1",
"order": -1,
"showTitle": true,
"className": "",
"visible": "true",
"disabled": "false"
},
{
"id": "e8ae1befc87a269b",
"type": "ui-page",
"name": "Dashbaord",
"ui": "19c2d65d89fdf992",
"path": "/page1",
"icon": "home",
"layout": "grid",
"theme": "6d123385f58e996d",
"order": -1,
"className": "",
"visible": "true",
"disabled": "false"
},
{
"id": "19c2d65d89fdf992",
"type": "ui-base",
"name": "ui-base",
"path": "/dashboard",
"includeClientData": true,
"acceptsClientConfig": [
"ui-notification",
"ui-control"
],
"showPathInSidebar": false,
"navigationStyle": "default"
},
{
"id": "6d123385f58e996d",
"type": "ui-theme",
"name": "Default",
"colors": {
"surface": "#ffffff",
"primary": "#0094ce",
"bgPage": "#eeeeee",
"groupBg": "#ffffff",
"groupOutline": "#cccccc"
},
"sizes": {
"pagePadding": "12px",
"groupGap": "12px",
"groupBorderRadius": "4px",
"widgetGap": "12px"
}
}
]
Jeg har sett en video som forklarer hvordan Node-RED blir brukt i en produksjonsfabrikk for Mercedes. Her er Node-RED ansvarlig for å injisere loggdata via SQL, kontrollere 3D-scannere som leser QR-koder, og kommunisere med en enkel blekkprinter.
På bare 12 timer ble det utviklet en løsning for å gjøre dette, samtidig som det ble kommunisert med en Siemens s7 PLC for data. Mye av kommunikasjonen var proprietær, så det var ikke mye informasjon tilgjengelig.
Dette systemet har kjørt helt feilfritt i over 2 år. Personen som laget det, fikk en telefon da det var behov for å øke kapasiteten på SQL-delen. Fordelen med Node-RED her er at selv om det har gått 2 år, er det relativt enkelt å sette seg inn i “koden” ettersom flyt logikken er helt lik i dag som den var for 2 år siden. Dette er i motsetning til å lese kode som andre har laget i for eksempel C#.
How to deploy Node-RED to hundreds of PLCs and IoT edge devices
I jobbsammenheng har jeg brukt Node-RED, på en flåte av Raspberry Pis. Hvor minimum 375 raspberry pier, kjører Node-RED, som leser og skriver data til en database, kontrollerer en fysisk motor og kommuniserer via MQTT til en hovedenhet, som og kan fjernstyre hver Raspberry ved behov.
Sluttbrukere
En av fordelene med Node-RED er at det er flytbasert, noe som gjør det lett tilgjengelig for sluttbrukere. Dette gir dem muligheten til å lage enkle automatiseringer selv, noe som kan gi dem muligheten til å lage en logikk de ikke allerede har, og tilpasse resultatene slik de ønsker.
Node-RED er designet for å kunne bygges inn i andre tjenester, og gir en viss grad av kontroll over hva en sluttbruker kan ha tilgang til. Utviklere kan legge inn begrensninger som gjør at de kun kan bruke allerede installerte noder og tillate andre ting.
Sluttnoter
Å utvikle i Node-RED er en unik opplevelse som krever en tilnærming som kan være forskjellig fra det de fleste utviklere er vant til. Selv om det ikke er særlig komplisert, er det viktig å forstå at en stor del av arbeidet består i å unngå unødvendig kompleksitet. En ryddig og oversiktlig arbeidsflyt (flow) er ofte en god arbeidsflyt, da det forbedrer lesbarheten og forebygger feil. Dette bidrar til å skape en mer effektiv og produktiv utviklingsprosess.
Når endringer gjøres i Node-RED, kan de oppleves og testes nesten umiddelbart. Dette gir en rask tilbakemeldingssløyfe som kan forbedre kvaliteten på koden. En av de største utfordringene med Node-RED er imidlertid å finne ut hvordan man best tester koden man har skrevet. Ofte er den mest effektive løsningen å bruke “Inject”- og “Debug”-nodene for å simulere og se resultatet. Dette gir utviklerne mulighet til å raskt identifisere og rette eventuelle feil.