node-red-contrib-thingsboard-gateway 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -14
- package/nodes/gateway_out.js +9 -0
- package/nodes/gateway_out.json +336 -0
- package/package.json +2 -2
- package/nodes/thingsboard-gateway.html +0 -44
- package/nodes/thingsboard-gateway.js +0 -37
package/README.md
CHANGED
|
@@ -1,16 +1,2 @@
|
|
|
1
1
|
# node-red-contrib-thingsboard-gateway
|
|
2
2
|
|
|
3
|
-
Send telemetry data from Node-RED to ThingsBoard Gateway using MQTT.
|
|
4
|
-
|
|
5
|
-
## Input
|
|
6
|
-
`msg.payload` should be a valid ThingsBoard gateway telemetry JSON.
|
|
7
|
-
|
|
8
|
-
## Example
|
|
9
|
-
|
|
10
|
-
```json
|
|
11
|
-
{
|
|
12
|
-
"deviceName": "sensor-01",
|
|
13
|
-
"telemetry": {
|
|
14
|
-
"temperature": 27.5
|
|
15
|
-
}
|
|
16
|
-
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
module.exports = function(RED) {
|
|
5
|
+
const subflowFile = path.join(__dirname,"gateway_out.json");
|
|
6
|
+
const subflowContents = fs.readFileSync(subflowFile);
|
|
7
|
+
const subflowJSON = JSON.parse(subflowContents);
|
|
8
|
+
RED.nodes.registerSubflow(subflowJSON);
|
|
9
|
+
}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "8d3bffe93912093b",
|
|
3
|
+
"type": "subflow",
|
|
4
|
+
"name": "gateway out",
|
|
5
|
+
"info": "Node-RED Subflow to use the [Thingsboard MQTT Gateway API](https://thingsboard.io/docs/reference/gateway-mqtt-api) for direct integration with FlexIoT.\r\n\r\n### Details\r\n\r\n#### Node Status\r\n\r\nThe node status color indicates the connection status to the Thingsboard platform.\r\n\r\n`Con`: connected / disconnected / errors (total)\r\n`Tel`: success / errors (total)\r\n`Attr`: success / errors (total)\r\n\r\n#### Device Connection\r\n\r\nUsed to connect a device to the Thingsboard platform.\r\nIt handles the connection process, including authentication and device registration.\r\n\r\nMessage properties:\r\n\r\n: api_method (string) : Must be set to \"connection\" for device connection.\r\n: device_name (string) : Device name to be targeted in Device List on FlexIoT.\r\n: device_type (string) : Device type, required for first connection. See FlexIoT Device Profile.\r\n: value (object) : Connection status.\r\n\r\nExample:\r\n\r\n```json\r\n{\r\n \"api_method\": \"connection\",\r\n \"device_name\": \"xinergis_32A3D\",\r\n \"device_type\": \"Xinergis Device\",\r\n \"value\": {\r\n \"active\": true\r\n }\r\n}\r\n```\r\n\r\n#### Attributes\r\n\r\nUsed to set device attributes.\r\nIt allows you to send key-value pairs as attributes to the device.\r\n\r\nMessage properties:\r\n\r\n: api_method (string) : Must be set to \"attributes\" for setting attributes.\r\n: device_name (string) : Device name to be targeted in Device List on FlexIoT.\r\n: value (object) : Key-value pairs representing the attributes.\r\n\r\nExample:\r\n\r\n```json\r\n{\r\n \"api_method\": \"attributes\",\r\n \"device_name\": \"xinergis_32A3D\",\r\n \"value\": {\r\n \"attribute_key_1\": \"value_1\",\r\n \"attribute_key_2\": \"value_2\"\r\n }\r\n}\r\n```\r\n\r\n#### Telemetry\r\n\r\nUsed to send telemetry data to the device.\r\nIt allows you to send various types of telemetry data.\r\n\r\nMessage properties:\r\n\r\n: api_method (string) : Must be set to \"telemetry\" for sending telemetry data.\r\n: device_name (string) : Device name to be targeted in Device List on FlexIoT.\r\n: value (object | array) : Key-value pairs representing the telemetry data.\r\n\r\nSingle object example:\r\n\r\n```json\r\n{\r\n \"api_method\": \"telemetry\",\r\n \"device_name\": \"xinergis_32A3D\",\r\n \"value\": {\r\n \"telemetry_key_1\": \"value_1\",\r\n \"telemetry_key_2\": \"value_2\"\r\n }\r\n}\r\n```\r\n\r\nArray example:\r\n\r\n```json\r\n{\r\n \"api_method\": \"telemetry\",\r\n \"device_name\": \"xinergis_32A3D\",\r\n \"value\": [\r\n {\r\n \"ts\": 1700000000000,\r\n \"values\": {\r\n \"telemetry_key_1\": \"value_1\",\r\n \"telemetry_key_2\": \"value_2\"\r\n }\r\n },\r\n {\r\n \"ts\": 1700000001000,\r\n \"values\": {\r\n \"telemetry_key_1\": \"value_3\",\r\n \"telemetry_key_2\": \"value_4\"\r\n }\r\n }\r\n ]\r\n}\r\n```\r\n\r\n### References\r\n\r\n* [Thingsboard MQTT Gateway API](https://thingsboard.io/docs/reference/gateway-mqtt-api)\r\n",
|
|
6
|
+
"category": "",
|
|
7
|
+
"in": [
|
|
8
|
+
{
|
|
9
|
+
"x": 360,
|
|
10
|
+
"y": 560,
|
|
11
|
+
"wires": [
|
|
12
|
+
{
|
|
13
|
+
"id": "4b7e9a3f7a1c5324"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"out": [],
|
|
19
|
+
"env": [
|
|
20
|
+
{
|
|
21
|
+
"name": "Server",
|
|
22
|
+
"type": "mqtt-broker",
|
|
23
|
+
"value": "",
|
|
24
|
+
"ui": {
|
|
25
|
+
"icon": "font-awesome/fa-globe",
|
|
26
|
+
"type": "conf-types"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"meta": {
|
|
31
|
+
"module": "gateway-out",
|
|
32
|
+
"type": "network",
|
|
33
|
+
"version": "1.0.0",
|
|
34
|
+
"author": "farisrfp <farisrafp@gmail.com>",
|
|
35
|
+
"license": "MIT"
|
|
36
|
+
},
|
|
37
|
+
"color": "#8083fa",
|
|
38
|
+
"inputLabels": [
|
|
39
|
+
"paylod-in"
|
|
40
|
+
],
|
|
41
|
+
"icon": "node-red/bridge-dash.svg",
|
|
42
|
+
"flow": [
|
|
43
|
+
|
|
44
|
+
{
|
|
45
|
+
"id": "aab53e74b7e5cb53",
|
|
46
|
+
"type": "function",
|
|
47
|
+
"z": "8d3bffe93912093b",
|
|
48
|
+
"name": "Connection Process",
|
|
49
|
+
"func": "const device_name = msg.payload.device_name;\nconst device_type = msg.payload.device_type;\nconst payload = msg.payload.value;\n\nif (typeof payload?.active !== 'boolean') {\n const connection_error = flow.get('connection_error') || 0;\n flow.set('connection_error', connection_error + 1);\n\n return null;\n}\n\nconst is_active = payload.active;\nmsg.topic = is_active ? 'v1/gateway/connect' : 'v1/gateway/disconnect';\nmsg.payload = is_active ? { device: device_name, type: device_type } : { device: device_name };\n\nconst connection_connected = flow.get('connection_connected') || 0;\nconst connection_disconnected = flow.get('connection_disconnected') || 0;\nconst connection_success = flow.get('connection_success') || 0;\nif (is_active) {\n flow.set('connection_connected', connection_connected + 1);\n} else {\n flow.set('connection_disconnected', connection_disconnected + 1);\n}\nflow.set('connection_success', connection_success + 1);\n\nreturn msg;",
|
|
50
|
+
"outputs": 1,
|
|
51
|
+
"timeout": 0,
|
|
52
|
+
"noerr": 0,
|
|
53
|
+
"initialize": "",
|
|
54
|
+
"finalize": "",
|
|
55
|
+
"libs": [],
|
|
56
|
+
"x": 1320,
|
|
57
|
+
"y": 520,
|
|
58
|
+
"wires": [
|
|
59
|
+
[
|
|
60
|
+
"a9dd9c6e8b0c3ef8"
|
|
61
|
+
]
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"id": "0c9017a47fbd43e3",
|
|
66
|
+
"type": "switch",
|
|
67
|
+
"z": "8d3bffe93912093b",
|
|
68
|
+
"name": "Switch API",
|
|
69
|
+
"property": "payload.api_method",
|
|
70
|
+
"propertyType": "msg",
|
|
71
|
+
"rules": [
|
|
72
|
+
{
|
|
73
|
+
"t": "eq",
|
|
74
|
+
"v": "connection",
|
|
75
|
+
"vt": "str"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"t": "eq",
|
|
79
|
+
"v": "attributes",
|
|
80
|
+
"vt": "str"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"t": "eq",
|
|
84
|
+
"v": "telemetry",
|
|
85
|
+
"vt": "str"
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"checkall": "true",
|
|
89
|
+
"repair": false,
|
|
90
|
+
"outputs": 3,
|
|
91
|
+
"x": 1050,
|
|
92
|
+
"y": 560,
|
|
93
|
+
"wires": [
|
|
94
|
+
[
|
|
95
|
+
"aab53e74b7e5cb53"
|
|
96
|
+
],
|
|
97
|
+
[
|
|
98
|
+
"7e858adb86eafa1c"
|
|
99
|
+
],
|
|
100
|
+
[
|
|
101
|
+
"bcfc701b1b986ff3"
|
|
102
|
+
]
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"id": "aef5609072e8f7cf",
|
|
107
|
+
"type": "function",
|
|
108
|
+
"z": "8d3bffe93912093b",
|
|
109
|
+
"name": "Summary Status",
|
|
110
|
+
"func": "const status = flow.get('status') || { fill: \"gray\", dot: \"fill\" }\n\nmsg = {};\nmsg.status = {\n fill: status.fill,\n shape: status.shape,\n text: status.text\n};\n\nnode.status(msg.status)\n\nreturn msg;",
|
|
111
|
+
"outputs": 1,
|
|
112
|
+
"timeout": 0,
|
|
113
|
+
"noerr": 0,
|
|
114
|
+
"initialize": "",
|
|
115
|
+
"finalize": "",
|
|
116
|
+
"libs": [],
|
|
117
|
+
"x": 2020,
|
|
118
|
+
"y": 660,
|
|
119
|
+
"wires": [
|
|
120
|
+
[]
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"id": "dc4e55611ccff866",
|
|
125
|
+
"type": "delay",
|
|
126
|
+
"z": "8d3bffe93912093b",
|
|
127
|
+
"name": "limit message",
|
|
128
|
+
"pauseType": "rate",
|
|
129
|
+
"timeout": "5",
|
|
130
|
+
"timeoutUnits": "seconds",
|
|
131
|
+
"rate": "1",
|
|
132
|
+
"nbRateUnits": "0.5",
|
|
133
|
+
"rateUnits": "second",
|
|
134
|
+
"randomFirst": "1",
|
|
135
|
+
"randomLast": "5",
|
|
136
|
+
"randomUnits": "seconds",
|
|
137
|
+
"drop": false,
|
|
138
|
+
"allowrate": false,
|
|
139
|
+
"outputs": 1,
|
|
140
|
+
"x": 2040,
|
|
141
|
+
"y": 520,
|
|
142
|
+
"wires": [
|
|
143
|
+
[
|
|
144
|
+
"ea599d3aca06a643"
|
|
145
|
+
]
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"id": "7e858adb86eafa1c",
|
|
150
|
+
"type": "function",
|
|
151
|
+
"z": "8d3bffe93912093b",
|
|
152
|
+
"name": "Attributes Process",
|
|
153
|
+
"func": "const device_name = msg.payload.device_name;\nconst payload = msg.payload.value;\n\nif (!device_name || msg.payload == null) {\n const attributes_error = flow.get('attributes_error') || 0;\n flow.set('attributes_error', attributes_error + 1);\n\n return null;\n}\n\nmsg.topic = 'v1/gateway/attributes';\nmsg.payload = { [device_name]: payload };\n\nconst attributes_success = flow.get('attributes_success') || 0;\nflow.set('attributes_success', attributes_success + 1);\n\nreturn msg;",
|
|
154
|
+
"outputs": 1,
|
|
155
|
+
"timeout": 0,
|
|
156
|
+
"noerr": 0,
|
|
157
|
+
"initialize": "",
|
|
158
|
+
"finalize": "",
|
|
159
|
+
"libs": [],
|
|
160
|
+
"x": 1310,
|
|
161
|
+
"y": 560,
|
|
162
|
+
"wires": [
|
|
163
|
+
[
|
|
164
|
+
"a9dd9c6e8b0c3ef8"
|
|
165
|
+
]
|
|
166
|
+
]
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"id": "cee336a87dd1a38f",
|
|
170
|
+
"type": "split",
|
|
171
|
+
"z": "8d3bffe93912093b",
|
|
172
|
+
"name": "Split Values",
|
|
173
|
+
"splt": "\\n",
|
|
174
|
+
"spltType": "str",
|
|
175
|
+
"arraySplt": "5",
|
|
176
|
+
"arraySpltType": "len",
|
|
177
|
+
"stream": false,
|
|
178
|
+
"addname": "",
|
|
179
|
+
"property": "payload.split",
|
|
180
|
+
"x": 1510,
|
|
181
|
+
"y": 600,
|
|
182
|
+
"wires": [
|
|
183
|
+
[
|
|
184
|
+
"b24e3d9340162324"
|
|
185
|
+
]
|
|
186
|
+
]
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"id": "bcfc701b1b986ff3",
|
|
190
|
+
"type": "function",
|
|
191
|
+
"z": "8d3bffe93912093b",
|
|
192
|
+
"name": "Telemetry Process",
|
|
193
|
+
"func": "let device_name = msg.payload.device_name\nconst payload = Array.isArray(msg.payload.value) ? msg.payload.value : [msg.payload.value];\n\nif (!device_name || typeof msg.payload == undefined) {\n const telemetry_error = flow.get('telemetry_error') || 0;\n flow.set('telemetry_error', telemetry_error + 1);\n return null;\n}\n\n/* Temporary for splittring payload */\nmsg.device_name = device_name;\ndevice_name = \"split\";\n\nmsg.topic = 'v1/gateway/telemetry';\nmsg.payload = { [device_name]: payload };\n\nconst telemetry_success = flow.get('telemetry_success') || 0;\nflow.set('telemetry_success', telemetry_success + 1);\n\nreturn msg;",
|
|
194
|
+
"outputs": 1,
|
|
195
|
+
"timeout": 0,
|
|
196
|
+
"noerr": 0,
|
|
197
|
+
"initialize": "",
|
|
198
|
+
"finalize": "",
|
|
199
|
+
"libs": [],
|
|
200
|
+
"x": 1310,
|
|
201
|
+
"y": 600,
|
|
202
|
+
"wires": [
|
|
203
|
+
[
|
|
204
|
+
"cee336a87dd1a38f"
|
|
205
|
+
]
|
|
206
|
+
]
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
"id": "b24e3d9340162324",
|
|
210
|
+
"type": "function",
|
|
211
|
+
"z": "8d3bffe93912093b",
|
|
212
|
+
"name": "Return Device Name",
|
|
213
|
+
"func": "const device_name = msg.device_name;\nconst data_array = msg.payload.split;\n\nmsg.payload = {\n [device_name]: data_array\n};\n\nreturn msg;\n",
|
|
214
|
+
"outputs": 1,
|
|
215
|
+
"timeout": 0,
|
|
216
|
+
"noerr": 0,
|
|
217
|
+
"initialize": "",
|
|
218
|
+
"finalize": "",
|
|
219
|
+
"libs": [],
|
|
220
|
+
"x": 1740,
|
|
221
|
+
"y": 600,
|
|
222
|
+
"wires": [
|
|
223
|
+
[
|
|
224
|
+
"a9dd9c6e8b0c3ef8"
|
|
225
|
+
]
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"id": "3380c50a90b10d49",
|
|
230
|
+
"type": "status",
|
|
231
|
+
"z": "8d3bffe93912093b",
|
|
232
|
+
"name": "",
|
|
233
|
+
"scope": [
|
|
234
|
+
"ea599d3aca06a643"
|
|
235
|
+
],
|
|
236
|
+
"x": 1560,
|
|
237
|
+
"y": 660,
|
|
238
|
+
"wires": [
|
|
239
|
+
[
|
|
240
|
+
"af3fc41d0edfe224"
|
|
241
|
+
]
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"id": "af3fc41d0edfe224",
|
|
246
|
+
"type": "function",
|
|
247
|
+
"z": "8d3bffe93912093b",
|
|
248
|
+
"name": "MQTT Publish Status",
|
|
249
|
+
"func": "flow.set(\"status\", msg.status)\n\nreturn msg;",
|
|
250
|
+
"outputs": 1,
|
|
251
|
+
"timeout": 0,
|
|
252
|
+
"noerr": 0,
|
|
253
|
+
"initialize": "",
|
|
254
|
+
"finalize": "",
|
|
255
|
+
"libs": [],
|
|
256
|
+
"x": 1760,
|
|
257
|
+
"y": 660,
|
|
258
|
+
"wires": [
|
|
259
|
+
[
|
|
260
|
+
"aef5609072e8f7cf"
|
|
261
|
+
]
|
|
262
|
+
]
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
"id": "4b7e9a3f7a1c5324",
|
|
266
|
+
"type": "function",
|
|
267
|
+
"z": "8d3bffe93912093b",
|
|
268
|
+
"name": "Format Device Name",
|
|
269
|
+
"func": "let oldKey = msg.payload.device_name;\nlet newKey = oldKey.replace(/_/g, \"-\").toUpperCase();\nmsg.payload.device_name = newKey;\nreturn msg;\n",
|
|
270
|
+
"outputs": 1,
|
|
271
|
+
"timeout": 0,
|
|
272
|
+
"noerr": 0,
|
|
273
|
+
"initialize": "",
|
|
274
|
+
"finalize": "",
|
|
275
|
+
"libs": [],
|
|
276
|
+
"x": 580,
|
|
277
|
+
"y": 560,
|
|
278
|
+
"wires": [
|
|
279
|
+
[
|
|
280
|
+
"7689c6c186fb5477"
|
|
281
|
+
]
|
|
282
|
+
]
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"id": "7689c6c186fb5477",
|
|
286
|
+
"type": "function",
|
|
287
|
+
"z": "8d3bffe93912093b",
|
|
288
|
+
"name": "Check Database",
|
|
289
|
+
"func": "const flexiot_devices = global.get(\"flexiot_devices\") || [];\nconst device_name = msg.payload.device_name;\n\nif (!flexiot_devices.includes(device_name)) {\n msg.payload.api_method = \"connection\";\n msg.payload.value.active = true;\n\n if (device_name.includes(\"IR\")) {\n msg.payload.device_type = \"PowerSense - IR Blaster Device\";\n }\n\n if (device_name.includes(\"METER\")) {\n msg.payload.device_type = \"PowerSense - Meter Device\";\n }\n\n if (device_name.includes(\"SWITCH\")) {\n msg.payload.device_type = \"PowerSense - Energy Device\";\n }\n\n if (device_name.includes(\"TEMP\")) {\n msg.payload.device_type = \"PowerSense - Temperature Sensor\";\n }\n\n if (device_name.includes(\"DOOR\")) {\n msg.payload.device_type = \"PowerSense - Door Sensor\";\n }\n\n if (device_name.includes(\"DR502\")) {\n msg.payload.device_type = \"KC-LINK - Stand Alone\";\n }\n\n flexiot_devices.push(device_name);\n global.set(\"flexiot_devices\", flexiot_devices);\n} \n\nreturn msg;\n\n// PZEM-004T — Single-phase energy monitor\n// JSY-MK-354 — 3-phase energy meter\n// NGSC-430 — Kobelindo compressor controller\n// TUF-2000 — Ultrasonic flow / power meter\n// XY-MD02",
|
|
290
|
+
"outputs": 1,
|
|
291
|
+
"timeout": 0,
|
|
292
|
+
"noerr": 0,
|
|
293
|
+
"initialize": "",
|
|
294
|
+
"finalize": "",
|
|
295
|
+
"libs": [],
|
|
296
|
+
"x": 830,
|
|
297
|
+
"y": 560,
|
|
298
|
+
"wires": [
|
|
299
|
+
[
|
|
300
|
+
"0c9017a47fbd43e3"
|
|
301
|
+
]
|
|
302
|
+
]
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
"id": "ea599d3aca06a643",
|
|
306
|
+
"type": "mqtt out",
|
|
307
|
+
"z": "8d3bffe93912093b",
|
|
308
|
+
"name": "Out",
|
|
309
|
+
"topic": "",
|
|
310
|
+
"qos": "",
|
|
311
|
+
"retain": "",
|
|
312
|
+
"respTopic": "",
|
|
313
|
+
"contentType": "",
|
|
314
|
+
"userProps": "",
|
|
315
|
+
"correl": "",
|
|
316
|
+
"expiry": "",
|
|
317
|
+
"broker": "${Server}",
|
|
318
|
+
"x": 2230,
|
|
319
|
+
"y": 520,
|
|
320
|
+
"wires": []
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
"id": "a9dd9c6e8b0c3ef8",
|
|
324
|
+
"type": "junction",
|
|
325
|
+
"z": "8d3bffe93912093b",
|
|
326
|
+
"x": 1900,
|
|
327
|
+
"y": 520,
|
|
328
|
+
"wires": [
|
|
329
|
+
[
|
|
330
|
+
"dc4e55611ccff866",
|
|
331
|
+
"aef5609072e8f7cf"
|
|
332
|
+
]
|
|
333
|
+
]
|
|
334
|
+
}
|
|
335
|
+
]
|
|
336
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-thingsboard-gateway",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Node-RED node for sending data to ThingsBoard via Gateway Device using MQTT protocol.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node-red",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"node-red": {
|
|
17
17
|
"nodes": {
|
|
18
|
-
"
|
|
18
|
+
"gateway-out": "nodes/gateway_out.js"
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
<script type="text/javascript">
|
|
2
|
-
RED.nodes.registerType("thingsboard-gateway", {
|
|
3
|
-
category: "network",
|
|
4
|
-
color: "#2C3E50",
|
|
5
|
-
defaults: {
|
|
6
|
-
name: { value: "" },
|
|
7
|
-
broker: { value: "mqtt://localhost:1883", required: true },
|
|
8
|
-
topic: { value: "v1/gateway/telemetry" },
|
|
9
|
-
username: { value: "" },
|
|
10
|
-
password: { value: "" }
|
|
11
|
-
},
|
|
12
|
-
inputs: 1,
|
|
13
|
-
outputs: 0,
|
|
14
|
-
icon: "bridge.svg",
|
|
15
|
-
label: function () {
|
|
16
|
-
return this.name || "ThingsBoard Gateway";
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
</script>
|
|
20
|
-
|
|
21
|
-
<div class="form-row">
|
|
22
|
-
<label>Name</label>
|
|
23
|
-
<input type="text" id="node-input-name">
|
|
24
|
-
</div>
|
|
25
|
-
|
|
26
|
-
<div class="form-row">
|
|
27
|
-
<label>Broker</label>
|
|
28
|
-
<input type="text" id="node-input-broker">
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
<div class="form-row">
|
|
32
|
-
<label>Topic</label>
|
|
33
|
-
<input type="text" id="node-input-topic">
|
|
34
|
-
</div>
|
|
35
|
-
|
|
36
|
-
<div class="form-row">
|
|
37
|
-
<label>Username</label>
|
|
38
|
-
<input type="text" id="node-input-username">
|
|
39
|
-
</div>
|
|
40
|
-
|
|
41
|
-
<div class="form-row">
|
|
42
|
-
<label>Password</label>
|
|
43
|
-
<input type="password" id="node-input-password">
|
|
44
|
-
</div>
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
module.exports = function (RED) {
|
|
2
|
-
function ThingsBoardGatewayNode(config) {
|
|
3
|
-
RED.nodes.createNode(this, config);
|
|
4
|
-
|
|
5
|
-
const node = this;
|
|
6
|
-
const mqtt = require("mqtt");
|
|
7
|
-
|
|
8
|
-
const client = mqtt.connect(config.broker, {
|
|
9
|
-
username: config.username,
|
|
10
|
-
password: config.password
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
client.on("connect", () => {
|
|
14
|
-
node.status({ fill: "green", shape: "dot", text: "connected" });
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
client.on("error", (err) => {
|
|
18
|
-
node.status({ fill: "red", shape: "ring", text: "error" });
|
|
19
|
-
node.error(err);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
node.on("input", (msg) => {
|
|
23
|
-
if (!msg.payload) return;
|
|
24
|
-
|
|
25
|
-
const topic = config.topic || "v1/gateway/telemetry";
|
|
26
|
-
const payload = JSON.stringify(msg.payload);
|
|
27
|
-
|
|
28
|
-
client.publish(topic, payload);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
node.on("close", () => {
|
|
32
|
-
client.end();
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
RED.nodes.registerType("thingsboard-gateway", ThingsBoardGatewayNode);
|
|
37
|
-
};
|