โ Node-red ์ค์ ํ์ผ(settings.js)
- ๋๋ ๋์ปค ์์ node-red ์ฌ๋ฆฐ ๊ฑฐ๋ผ์ ์๋ ๋ช ๋ น์ด๋ก settings.js ํ์ผ์ ์ฐพ์ ์ ์์๋ค.
> docker exec -it nodered /bin/bash
> vi /data/settings.js
- node-red๊ฐ ์์๋ ๋ ์ต์ด๋ก ํ ๋ฒ๋ง ์ ์ฉ๋๋ ์ค์ ์ด๋ค.
- ์ค์ ํ์ผ์ ์์ ํ ์ ์ฉํ๋ ค๋ฉด node-red๋ฅผ ๊ป๋ค ์ผ์ผ ํ๋ค.
๐ httpAdminRoot ์ค์
- httpAdminRoot์ ๊ฒฝ๋ก๋ฅผ ์ค์ ํด์ฃผ๋ฉด, ํด๋น ๊ฒฝ๋ก๊ฐ ๋ฃจํธ ๊ฒฝ๋ก๊ฐ ๋๋ค.
- ๋ํดํธ ๋ฃจํธ ๊ฒฝ๋ก๋ `/` ์ด๋ฏ๋ก `http://์๋ฒ์์ดํผ:1880` ๋ก ์ ์ํ๋ฉด ๋๋ค.
๐ adminAuth ์ค์
- ๋ ธ๋ ๋ ๋ editor๋ admin API๋ฅผ ์ฌ์ฉํ ๋ ์ฌ์ฉ์ ์ธ์ฆ์ ์ด๋ป๊ฒ ํ ์ง ์ค์ ํ๋ ๋ถ๋ถ
- ๋ํดํธ๋ก๋ ์ธ์ฆ ์์ด ์ฌ์ฉํ ์ ์๋๋ก ๋์ด ์๋ค.
- username์ ํจ์ค์๋(bcrypt๋ก ์ํธํ๋ ํํ)๋ฅผ ์ ์ด์ฃผ๊ณ , permissions ์๋ * ๋๋ read๋ฅผ ์ ์ด์ฃผ๋ฉด ๋๋ค.
- ์ฌ์ฉ์ ์ธ์ฆ์ด ํ์ํ๋๋ก ์ค์ ํ ๊ฒฝ์ฐ, ๋
ธ๋๋ ๋ API๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด
- username๊ณผ password๋ฅผ ์ด์ฉํด ํ ํฐ์ ๋ฐ๊ธ๋ฐ์์,
- ์์ฒญ์ ๋ณด๋ผ ๋ Authorization ํค๋์ ๋ฐ๊ธ๋ฐ์ ํ ํฐ์ ๋ด์์ฃผ์ด์ผ ํ๋ค.
โ Node-red API
๐ GET /flows
- ํ์ฌ ๋ฐฐํฌ๋์ด์๋ flows.json ํ์ผ์ ์๋ต body์ ๋ด์ ๋ณด๋ธ๋ค.
๐ POST /flows
- ํ์ฌ flows๋ฅผ ์์ฒญ body์ ๋ด๊ธด flows.json์ผ๋ก ์์ ํ์ฌ ๋ฐฐํฌํ๋ค.
https://nodered.org/docs/api/admin/methods/
๐ฃ flows.json
- json ๋ฐฐ์ด ํํ์ด๊ณ ๊ฐ json ๊ฐ์ฒด ํ๋๋ ํญ ๋๋ ๋ ธ๋์ด๋ค.
- Node-red์์ ์์ฃผ ์ฌ์ฉํ๋ ๋ ธ๋๋ค์ด ํด๋์ค ํํ๋ก ์ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋์ง ์ฐพ์๋ดค์ง๋ง,
- Java์๋, JavaScript์๋ ์์์.
→ flows ์์ ํ๋ ค๋ฉด, ์ฐ๋ฆฌ๊ฐ ์ด๋ป๊ฒ๋ flows.json์ ์ง์ ์์ฑํด์ POST /flows ์์ฒญ ๋ณด๋ด์ผํจ
flows.json ์์
[
{
"id": "9b9dc9d130c425ba",
"type": "mqtt in",
"z": "f6f2187d.f17ca8",
"name": "",
"topic": "#",
"qos": "2",
"datatype": "auto-detect",
"broker": "e4c4de3f1d988aba",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 270,
"y": 260,
"wires": [
[
"478118ba5279275d"
]
]
},
{
"id": "7c06fcd191b77fab",
"type": "mqtt out",
"z": "f6f2187d.f17ca8",
"name": "",
"topic": "",
"qos": "",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "e4c4de3f1d988aba",
"x": 550,
"y": 260,
"wires": []
},
{
"id": "478118ba5279275d",
"type": "function",
"z": "f6f2187d.f17ca8",
"name": "function 1",
"func": "msg.payload.time = Math.floor(Date.now()/1000);\\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 420,
"y": 260,
"wires": [
[
"7c06fcd191b77fab",
"6c977802da75f838"
]
]
},
{
"id": "6c977802da75f838",
"type": "debug",
"z": "f6f2187d.f17ca8",
"name": "debug 1",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 580,
"y": 180,
"wires": []
},
{
"id": "e4c4de3f1d988aba",
"type": "mqtt-broker",
"name": "๋งฅ๋ฏธ๋",
"broker": "192.168.70.203",
"port": "1883",
"clientid": "",
"autoConnect": true,
"usetls": false,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"autoUnsubscribe": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willPayload": "",
"willMsg": {},
"userProps": "",
"sessionExpiry": ""
}
]
- ์ฒซ ๋ฒ์งธ ์์: flow ์ถ๊ฐ
POST http://localhost:1880/flows
[
{
"id": "edc211502dc456d3",
"type": "mqtt in",
"z": "e30ff5fe7777e085",
"name": "",
"topic": "#",
"qos": "2",
"datatype": "auto-detect",
"broker": "4f5d917ba7bff899",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 470,
"y": 380,
"wires": [
[
"f77710ba99621141"
]
]
},
{
"id": "f77710ba99621141",
"type": "function",
"z": "e30ff5fe7777e085",
"name": "add time",
"func": "msg.payload.time = Math.floor(Date.now() / 1000);\\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 620,
"y": 380,
"wires": [
[
"0c3c71a50fcaef03"
]
]
},
{
"id": "0c3c71a50fcaef03",
"type": "mqtt out",
"z": "e30ff5fe7777e085",
"name": "",
"topic": "",
"qos": "",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "4f5d917ba7bff899",
"x": 770,
"y": 380,
"wires": []
},
{
"id": "4f5d917ba7bff899",
"type": "mqtt-broker",
"name": "๋งฅ๋ฏธ๋",
"broker": "192.168.70.203",
"port": "1883",
"clientid": "",
"autoConnect": true,
"usetls": false,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"autoUnsubscribe": true,
"birthTopic": "",
"birthQos": "0",
"birthRetain": "false",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closeRetain": "false",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willRetain": "false",
"willPayload": "",
"willMsg": {},
"userProps": "",
"sessionExpiry": ""
}
]
์์ฒญ ๋ณด๋ด๋ฉด “ํ๋ก์ฐ๊ฐ ๋ณ๊ฒฝ๋์์ต๋๋ค” ๋ผ๊ณ ํ์๋๋ฉด์ ์๋ ๋ฐฐํฌ๋จ
- ๋ ๋ฒ์งธ ์์: ์ฌ๋ฌ ํญ ์ถ๊ฐ
type: tab
id: ํญ ์์ด๋
z : ๋ ธ๋๊ฐ ์ํ ํญ์ ์์ด๋
POST http://localhost:1880/flows
[
{
"id": "ababab",
"type": "tab",
"label": "Flow ONE",
"disabled": false,
"info": ""
},
{
"id": "8968361bdf2072f1",
"type": "inject",
"z": "ababab",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 600,
"y": 440,
"wires": [
[
"c48c9fc37e393400"
]
]
},
{
"id": "c48c9fc37e393400",
"type": "debug",
"z": "ababab",
"name": "debug 1",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 770,
"y": 440,
"wires": []
},
{
"id": "aaabbbb",
"type": "tab",
"label": "Flow TWO",
"disabled": false,
"info": ""
},
{
"id": "bbbbbddddd",
"type": "function",
"z": "aaabbbb",
"name": "function",
"func": "msg.payload.time = Math.floor(Date.now()/1000);\\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 420,
"y": 260,
"wires": [
[
"7c06fcd191b77fab"
]
]
}
]
โ Auth ์ค์ ํ๊ธฐ
- ๊ณต์ ๋ฌธ์: https://nodered.org/docs/api/admin/
๐ GET /auth/login (Authentication ์ ๋ณด ํ์ธํ๊ธฐ)
- settings.json์ adminAuth ๋ณ๋๋ก ์ค์ ๋์ด ์์ง ์์ผ๋ฉด, ์๋ต ๋ฐ๋์ ์๋ฌด ๊ฒ๋ ๋ด๊ธฐ์ง ์๊ณ ์ด
- settings.json์ adminAuth ์ค์ ๋์ด ์์ผ๋ฉด, ์๋ต ๋ฐ๋์ Authentication scheme์ด ๋ด๊ฒจ์ ์ด
- ์์์ ๋งํ์ง๋ง, settings.js์ node-red๊ฐ ์์๋ ๋ ์ต์ด ํ ๋ฒ ์ ์ฉ๋๋ ์ค์ ์ด๋ค.
- ๊ทธ๋์ ์ค๊ฐ์ ๊ณ์ ์ ์ถ๊ฐํ๊ฑฐ๋ ์ธ์ฆ ๋ฐฉ์์ ๋ฐ๊พธ๊ณ ์ถ์ผ๋ฉด settings.js ํ์ผ์ ์์ ํ ๋ค ๋ ธ๋๋ ๋๋ฅผ ์ฌ์์ ํด์ฃผ์ด์ผ ํ๋ค.
- settings.js์ ์์ ํ๋ API๋ ๋ฐ๋ก ์๊ณ , ์ง์ ์๋ฒ์ ๋ค์ด๊ฐ์ ์์ ํด์ฃผ์ด์ผ ํ๋ค.
- (Node.js๊ฐ์ ๊ฒฝ์ฐ node-red๋ฅผ imbedํ๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋์์ ๋ฐ๋ก settings.js ์ค์ ์ ํ ์ ์๊ธด ํจ)
๐ settings.js adminAuth์ค์
- username: ์ ์ ์ด๋ฆ
- password: bcrypt๋ก ์ธ์ฝ๋ฉ ๋ ํด์๊ฐ
- permissions: * ๋๋ read ์ค ํ๋
์ค์ ํ์ผ ์์ ํ ๋ ธ๋๋ ๋ restart ํ๋ฉด ์ ์ฉ๋๋ค.
๐ POST /auth/token (ํ ํฐ ๋ฐ๊ธ๋ฐ๊ธฐ)
body์ ํ์ ์ ๋ณด๋ค์ ๋ด์์ POST ์์ฒญ์ ๋ณด๋ด๋ฉด ํ ํฐ์ด ์๋ต์ผ๋ก ์จ๋ค.
- client_id : node-red-admin ๋๋ node-red-editor ๋ ์ค ํ๋ ์ ์ด์ฃผ์ด์ผ ํ๋ค.
- grant_type : ๋ฌด์กฐ๊ฑด password๋ผ๊ณ ์ ์ด์ฃผ์ด์ผ ํ๋ค.
- scope: * ๋๋ read ์ค ํ๋ ์ ์ด์ฃผ์ด์ผ ํ๋ค.
- username: ์ธ์ฆ์ ์ฌ์ฉํ ์ ์ ์ด๋ฆ
- password: ์ธ์ฆ์ ํ์ํ ํจ์ค์๋(์ํธํ๋์ง ์์ plain text)
์๋ชป๋ ์ ๋ณด๋ก post ๋ณด๋ด๋ฉด 403 ์๋ต๊ณผ ๋น๋ฐ๋ฒํธ ํ๋ ธ๋ค๋ ๋ฉ์์ง๊ฐ ์ค๊ณ ํ ํฐ์ ๋ฐ๊ธ๋์ง ์๋๋ค.
๐ ๋ฐ๊ธ๋ฐ์ ํ ํฐ์ผ๋ก node-red API ์ด์ฉํ๊ธฐ
- ์ด์ API๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด Authorization ํค๋์ “Bearer [์์์ ๋ฐ๊ธ๋ฐ์ ํ ํฐ]”์ ๋ด์์ฃผ์ด์ผ ํ๋ค.
ํ ํฐ ์์ด GET /flows ์์ฒญ ๋ณด๋ด๋ฉด, 401 ๋ฌ๋ค.
ํ ํฐ์ ๋ฃ์ด์ฃผ๋ฉด API ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
'๊ฐ์ธ ๊ณต๋ถ > IoT' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
docker ์์ telegraf, influxdb(1.x) ์ปจํ ์ด๋ ์ฌ๋ ค์ mqtt ์ผ์ ๋ฐ์ดํฐ ์์งํ๊ธฐ (1) | 2024.11.27 |
---|---|
docker ์์ telegraf, influxdb(2.x) ์ปจํ ์ด๋ ์ฌ๋ ค์ mqtt ์ผ์ ๋ฐ์ดํฐ ์์งํ๊ธฐ (1) | 2024.11.26 |
MQTT (2) | 2023.11.27 |
[Node-red] flow ์์ฑ (0) | 2023.11.21 |