@operato/scene-mqtt 0.1.3

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.
@@ -0,0 +1,110 @@
1
+ # MQTT
2
+
3
+ MQTT broker에 연결되어, 설정된 topic 데이터를 publish/subscribe하는 데이타소스 컴포넌트이다.
4
+
5
+ - [MQTT 웹소켓 프로토콜](http://www.steves-internet-guide.com/mqtt-websockets/)를 사용한다.
6
+ - publish
7
+ - 이 컴포넌트의 value를 변경하면, 설정된 topic으로 value를 publish한다.
8
+ - subscribe
9
+ - 설정된 topic으로 subscribe되는 데이타를 서브스크라이브해서 data를 변경한다.
10
+ - data가 변경되면 데이타바인딩이 작동한다.
11
+
12
+ ## properties
13
+
14
+ ### MQTT 브로커로 mosquitto를 사용한 경우
15
+
16
+ - broker : hostname of the broker
17
+ - port : websocket service port number (default 1884)
18
+ - path : '/mqtt'
19
+ - user : username or blank
20
+ - password : password or blank
21
+ - topic : topic
22
+ - qos : QOS level [0, 1, 2]
23
+ - client-id : (unique) client id
24
+
25
+ ```
26
+ 클라이언트 아이디는 (브로커 입장에서) 유일한 연결 노드의 이름을 의미하며, 브로커에서 모니터링하기 위한 용도로 유일하게 적어준다.
27
+ 클라이언트 아이디 속성을 비워두면, 자동으로 'THINGS-BOARD-{role}-{timestamp}‘로 자동 생성된다.
28
+ 클라이언트 아이디 속성을 입력하면, 자동으로 '{client-id}-{role}-{timestamp}'로 자동 생성된다.
29
+ 클라이언트 아이디 속성에 timestamp를 추가하는 이유는, 유일한 아이디를 만들기 위해서이다.
30
+ ```
31
+
32
+ - data-format : [Plain Text, JSON]
33
+ - retain : true or false
34
+ - ssl : true or false (false)
35
+
36
+ ### RabbitMQ의 MQTT-Websocket 플러그인을 사용한 경우
37
+
38
+ - broker : hostname of the broker
39
+ - port : websocket service port number (default 15675)
40
+ - path : '/ws'
41
+ - user : username or blank
42
+ - password : password or blank
43
+ - topic : topic
44
+ - qos : QOS level [0, 1, 2]
45
+ - client-id : (unique) client id
46
+
47
+ ```
48
+ 클라이언트 아이디는 (브로커 입장에서) 유일한 연결 노드의 이름을 의미하며, 브로커에서 모니터링하기 위한 용도로 유일하게 적어준다.
49
+ 클라이언트 아이디 속성을 비워두면, 자동으로 'THINGS-BOARD-{role}-{timestamp}‘로 자동 생성된다.
50
+ 클라이언트 아이디 속성을 입력하면, 자동으로 '{client-id}-{role}-{timestamp}'로 자동 생성된다.
51
+ 클라이언트 아이디 속성에 timestamp를 추가하는 이유는, 유일한 아이디를 만들기 위해서이다.
52
+ ```
53
+
54
+ - data-format : [Plain Text, JSON]
55
+ - retain : true or false
56
+ - ssl : true or false (false)
57
+
58
+ ## Rabbit MQ의 MQTT-Websocket 플러그인을 사용하는 경우 메시지 Exchange
59
+
60
+ ```
61
+ When using the MQTT-Websocket plugin of Rabbit MQ,
62
+ It is routed by a durable'topic' type of'amq.topic' exchange.
63
+ Therefore, the topic attribute of the MQTT Data Source above serves as a routing key.
64
+
65
+ To be able to receive from MQTT Data Source using AMQP of Rabbit MQ,
66
+ See the javascript sample code below.
67
+ ```
68
+
69
+ ```
70
+ var amqp = require('amqplib/callback_api');
71
+
72
+ amqp.connect('amqp://hatiolab:hatiolab@mq.hatiolab.com', function(err, conn) {
73
+ if(err) {
74
+ console.error(err);
75
+ return;
76
+ }
77
+
78
+ conn.createChannel(function (err, ch) {
79
+ // Set the exchange to amq.topic and set the durable option to true.
80
+ var ex = 'amq.topic';
81
+
82
+ ch.assertExchange(ex, 'topic', { durable: true });
83
+
84
+ var location = {
85
+ x: 100,
86
+ y: 200
87
+ };
88
+
89
+ // When the topic property is set to location.
90
+ ch.publish(ex, 'location', new Buffer(JSON.stringify(location)));
91
+ });
92
+ });
93
+ ```
94
+
95
+ ## Creating an MQTT environment with mosquitto (based on macOS)
96
+
97
+ ### MQTT 브로커로 mosquitto 설치하기
98
+
99
+ - homebrew를 이용해서 mosquitto를 설치한다.
100
+
101
+ ```
102
+ $ brew install mosquitto
103
+ ```
104
+
105
+ - Things Scene은 브라우저용이므로, MQTT 브로커에 웹소켓으로 접속할 수 있어야 한다. 그래서, mosquitto에 웹서비스 기능을 활성화한다.
106
+
107
+ ```
108
+ $ echo -e "listener 1884\nprotocol websockets\nlistener 1883\nprotocol mqtt" >> /usr/local/opt/mosquitto/etc/mosquitto/mosquitto.conf
109
+ $ brew services restart mosquitto
110
+ ```
@@ -0,0 +1,110 @@
1
+ # MQTT
2
+
3
+ It is a data source component that connects to the MQTT broker and publishes/subscribes to the topic data set.
4
+
5
+ - Use [MQTT Websockets Protocol](http://www.steves-internet-guide.com/mqtt-websockets/).
6
+ - Publish
7
+ -When the value of this component is changed, the value will be published to the set topic.
8
+ - Subscribe
9
+ -Subscribe to subscribed topic data and change the data.
10
+ -When data is changed, data binding is valid.
11
+
12
+ ## properties
13
+
14
+ ### When using mosquitto as MQTT broker
15
+
16
+ - broker : hostname of the broker
17
+ - port : websocket service port number (default 1884)
18
+ - path : '/mqtt'
19
+ - user : username or blank
20
+ - password : password or blank
21
+ - topic : topic
22
+ - qos : QOS level [0, 1, 2]
23
+ - client-id : (unique) client id
24
+
25
+ ```
26
+ The client ID refers to the name of the only connected node (from the broker's point of view), and it is uniquely written for monitoring in the broker.
27
+ If the client ID attribute is left blank, it is automatically created as'THINGS-BOARD-{role}-{timestamp}'.
28
+ When the client ID attribute is entered, it is automatically created as'{client-id}-{role}-{timestamp}'.
29
+ The reason for adding timestamp to the client ID attribute is to create a unique ID.
30
+ ```
31
+
32
+ - data-format : [Plain Text, JSON]
33
+ - retain : true or false
34
+ - ssl : true or false (false)
35
+
36
+ ### When using RabbitMQ's MQTT-Websocket plugin
37
+
38
+ - broker : hostname of the broker
39
+ - port : websocket service port number (default 15675)
40
+ - path : '/ws'
41
+ - user : username or blank
42
+ - password : password or blank
43
+ - topic : topic
44
+ - qos : QOS level [0, 1, 2]
45
+ - client-id : (unique) client id
46
+
47
+ ```
48
+ The client ID refers to the name of the only connected node (from the broker's point of view), and it is uniquely written for monitoring in the broker.
49
+ If the client ID attribute is left blank, it is automatically created as'THINGS-BOARD-{role}-{timestamp}'.
50
+ When the client ID attribute is entered, it is automatically created as'{client-id}-{role}-{timestamp}'.
51
+ The reason for adding timestamp to the client ID attribute is to create a unique ID.
52
+ ```
53
+
54
+ - data-format : [Plain Text, JSON]
55
+ - retain : true or false
56
+ - ssl : true or false (false)
57
+
58
+ ### Message exchange when using Rabbit MQ's MQTT-Websocket plug-in
59
+
60
+ ```
61
+ 使用Rabbit MQ的MQTT-Websocket插件时,
62
+ 由durable 'topic'类型的“ amq.topic”的exchange来路由。
63
+ 因此,上述MQTT数据源的主题属性用作路由键。
64
+
65
+ 为了从Rabbit MQ的AMQP获取MQTT Data Source,
66
+ 请参见下面的javascript示例代码。
67
+ ```
68
+
69
+ ```js
70
+ var amqp = require('amqplib/callback_api');
71
+
72
+ amqp.connect('amqp://hatiolab:hatiolab@mq.hatiolab.com', function(err, conn) {
73
+ if(err) {
74
+ console.error(err);
75
+ return;
76
+ }
77
+
78
+ conn.createChannel(function (err, ch) {
79
+ // Set the exchange to amq.topic and set the durable option to true.
80
+ var ex = 'amq.topic';
81
+
82
+ ch.assertExchange(ex, 'topic', { durable: true });
83
+
84
+ var location = {
85
+ x: 100,
86
+ y: 200
87
+ };
88
+
89
+ // When the topic property is set to location.
90
+ ch.publish(ex, 'location', new Buffer(JSON.stringify(location)));
91
+ });
92
+ });
93
+ ```
94
+
95
+ ## Creating an MQTT environment with mosquitto (based on macOS)
96
+
97
+ ### Install mosquitto as MQTT broker
98
+
99
+ - Use homebrew to install mosquitto.
100
+
101
+ ```
102
+ $ brew install mosquitto
103
+ ```
104
+
105
+ - Things Scene is executed in the browser, so it needs to connect to the MQTT proxy via Web Socket. Therefore, you need to enable the Web service function in mosquitto.
106
+
107
+ ```sh
108
+ $ echo -e "listener 1884\nprotocol websockets\nlistener 1883\nprotocol mqtt" >> /usr/local/opt/mosquitto/etc/mosquitto/mosquitto.conf
109
+ $ brew services restart mosquitto
110
+ ```
@@ -0,0 +1,108 @@
1
+ # MQTT
2
+
3
+ 是连接到MQTT代理并发布/订阅设置的主题数据的数据源组件。
4
+
5
+ - 使用 [MQTT Websockets协议](http://www.steves-internet-guide.com/mqtt-websockets/)。
6
+ - 发布
7
+ - 更改此组件的值时,该值将发布到设置的主题。
8
+ - 订阅
9
+ - 订阅预订的主题数据并更改数据。
10
+ - 更改数据时,数据绑定有效。
11
+
12
+ ## properties
13
+
14
+ ### 使用mosquitto作为MQTT代理时
15
+
16
+ - 代理 : hostname of the broker
17
+ - 端口 : websocket service port number (default 1884)
18
+ - 路径 : '/mqtt'
19
+ - 用户 : username or blank
20
+ - 密码 : password or blank
21
+ - 主题 : topic
22
+ - qos : QOS level [0, 1, 2]
23
+ - 客户端ID : (unique) client id
24
+
25
+ ```
26
+ 从代理的角度来看,客户端ID是指唯一连接的节点的名称。
27
+ 如果客户端ID属性留空,则会自动将其创建为“ THINGS-BOARD- {role}-{timestamp}”。
28
+ 输入客户ID属性后,系统会自动将其创建为“ {client-id}-{role}-{timestamp}”。
29
+ ```
30
+
31
+ - 数据格式 : [Plain Text, JSON]
32
+ - 保持 : true or false
33
+ - ssl : true or false (false)
34
+
35
+ ### 使用RabbitMQ的MQTT-Websocket插件时
36
+
37
+ - 代理 : hostname of the broker
38
+ - 端口 : websocket service port number (default 15675)
39
+ - 路径 : '/ws'
40
+ - 用户 : username or blank
41
+ - 密码 : password or blank
42
+ - 主题 : topic
43
+ - qos : QOS level [0, 1, 2]
44
+ - 客户端ID : (unique) client id
45
+
46
+ ```
47
+ 从代理的角度来看,客户端ID是指唯一连接的节点的名称。
48
+ 如果客户端ID属性留空,则会自动将其创建为“ THINGS-BOARD- {role}-{timestamp}”。
49
+ 输入客户ID属性后,系统会自动将其创建为“ {client-id}-{role}-{timestamp}”。
50
+ ```
51
+
52
+ - 数据格式 : [Plain Text, JSON]
53
+ - 保持 : true or false
54
+ - ssl : true or false (false)
55
+
56
+ ### 使用Rabbit MQ的MQTT-Websocket插件时的消息交换
57
+
58
+ ```
59
+ 使用Rabbit MQ的MQTT-Websocket插件时,
60
+ 由durable 'topic'类型的“ amq.topic”的exchange来路由。
61
+ 因此,上述MQTT数据源的主题属性用作路由键。
62
+
63
+ 为了从Rabbit MQ的AMQP获取MQTT Data Source,
64
+ 请参见下面的javascript示例代码。
65
+ ```
66
+
67
+ ```js
68
+ var amqp = require('amqplib/callback_api');
69
+
70
+ amqp.connect('amqp://hatiolab:hatiolab@mq.hatiolab.com', function(err, conn) {
71
+ if(err) {
72
+ console.error(err);
73
+ return;
74
+ }
75
+
76
+ conn.createChannel(function (err, ch) {
77
+ // exchange配置为amq.topic, durable option为true.
78
+ var ex = 'amq.topic';
79
+
80
+ ch.assertExchange(ex, 'topic', { durable: true });
81
+
82
+ var location = {
83
+ x: 100,
84
+ y: 200
85
+ };
86
+
87
+ // topic属性为location时
88
+ ch.publish(ex, 'location', new Buffer(JSON.stringify(location)));
89
+ });
90
+ });
91
+ ```
92
+
93
+ ## 使用mosquitto创建MQTT环境(基于macOS)
94
+
95
+ ### 将mosquitto安装为MQTT代理
96
+
97
+ - 使用homebrew安装mosquitto。
98
+
99
+ ```sh
100
+ $ brew install mosquitto
101
+ ```
102
+
103
+ - Things Scene执行于浏览器,因此需要能够通过Web Socket连接到MQTT代理。 因此,需要在mosquitto中启用Web服务功能。
104
+
105
+ ```sh
106
+ $ echo -e "listener 1884\nprotocol websockets\nlistener 1883\nprotocol mqtt" >> /usr/local/opt/mosquitto/etc/mosquitto/mosquitto.conf
107
+ $ brew services restart mosquitto
108
+ ```
package/icons/mqtt.png ADDED
Binary file
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@operato/scene-mqtt",
3
+ "version": "0.1.3",
4
+ "description": "MQTT integration component for things-scene",
5
+ "things-scene": true,
6
+ "browser": "src/index.js",
7
+ "author": "heartyoh",
8
+ "license": "MIT",
9
+ "publishConfig": {
10
+ "access": "public",
11
+ "@operato:registry": "https://registry.npmjs.org"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/things-scene/operato-scene.git",
16
+ "directory": "packages/mqtt"
17
+ },
18
+ "scripts": {
19
+ "serve": "tsc && things-factory-dev",
20
+ "start": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"wds\"",
21
+ "build": "tsc",
22
+ "prepublish": "tsc",
23
+ "lint": "eslint --ext .ts,.html . --ignore-path .gitignore && prettier \"**/*.ts\" --check --ignore-path .gitignore",
24
+ "format": "eslint --ext .ts,.html . --fix --ignore-path .gitignore && prettier \"**/*.ts\" --write --ignore-path .gitignore",
25
+ "migration": "things-factory-migration"
26
+ },
27
+ "dependencies": {
28
+ "@hatiolab/things-scene": "^2.7.33",
29
+ "mqtt": "^4.3.4"
30
+ },
31
+ "devDependencies": {
32
+ "@hatiolab/prettier-config": "^1.0.0",
33
+ "@operato/board": "^0.3.20",
34
+ "@things-factory/builder": "^4.0.38",
35
+ "@things-factory/operato-board": "^4.0.38",
36
+ "@typescript-eslint/eslint-plugin": "^4.33.0",
37
+ "@typescript-eslint/parser": "^4.33.0",
38
+ "@web/dev-server": "^0.1.28",
39
+ "concurrently": "^5.3.0",
40
+ "eslint": "^7.32.0",
41
+ "eslint-config-prettier": "^8.3.0",
42
+ "husky": "^4.3.8",
43
+ "lint-staged": "^10.5.4",
44
+ "prettier": "^2.4.1",
45
+ "tslib": "^2.3.1",
46
+ "typescript": "^4.5.2"
47
+ },
48
+ "prettier": "@hatiolab/prettier-config",
49
+ "husky": {
50
+ "hooks": {
51
+ "pre-commit": "lint-staged"
52
+ }
53
+ },
54
+ "lint-staged": {
55
+ "*.ts": [
56
+ "eslint --fix",
57
+ "prettier --write"
58
+ ]
59
+ },
60
+ "gitHead": "f3275af95afaf8389224e1e507df6155cbf39382"
61
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ /*
2
+ * Copyright © HatioLab Inc. All rights reserved.
3
+ */
4
+ export { default as Mqtt } from './mqtt'
package/src/mqtt.ts ADDED
@@ -0,0 +1,245 @@
1
+ import mqtt from 'mqtt'
2
+
3
+ /*
4
+ * Copyright © HatioLab Inc. All rights reserved.
5
+ */
6
+ import { Component, DataSource, Properties, RectPath, Shape } from '@hatiolab/things-scene'
7
+
8
+ const NATURE = {
9
+ mutable: false,
10
+ resizable: true,
11
+ rotatable: true,
12
+ properties: [
13
+ {
14
+ type: 'string',
15
+ label: 'broker',
16
+ name: 'broker',
17
+ placeholder: 'WebSocket hostname'
18
+ },
19
+ {
20
+ type: 'number',
21
+ label: 'port',
22
+ name: 'port',
23
+ placeholder: '15675'
24
+ },
25
+ {
26
+ type: 'string',
27
+ label: 'path',
28
+ name: 'path',
29
+ placeholder: '/mqtt or /ws'
30
+ },
31
+ {
32
+ type: 'string',
33
+ label: 'user',
34
+ name: 'user'
35
+ },
36
+ {
37
+ type: 'string',
38
+ label: 'password',
39
+ name: 'password',
40
+ property: 'password'
41
+ },
42
+ {
43
+ type: 'string',
44
+ label: 'topic',
45
+ name: 'topic'
46
+ },
47
+ {
48
+ type: 'number',
49
+ label: 'qos',
50
+ name: 'qos',
51
+ placeholder: '0..2'
52
+ },
53
+ {
54
+ type: 'string',
55
+ label: 'client-id',
56
+ name: 'clientId'
57
+ },
58
+ {
59
+ type: 'select',
60
+ label: 'data-format',
61
+ name: 'dataFormat',
62
+ property: {
63
+ options: [
64
+ {
65
+ display: 'Plain Text',
66
+ value: 'text'
67
+ },
68
+ {
69
+ display: 'JSON',
70
+ value: 'json'
71
+ }
72
+ ]
73
+ }
74
+ },
75
+ {
76
+ type: 'checkbox',
77
+ label: 'retain',
78
+ name: 'retain'
79
+ },
80
+ {
81
+ type: 'checkbox',
82
+ label: 'ssl',
83
+ name: 'ssl'
84
+ }
85
+ ],
86
+ 'value-property': 'message',
87
+ help: 'scene/component/mqtt'
88
+ }
89
+
90
+ const MQTT_IMAGE =
91
+ 'data:image/png;base64,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'
92
+
93
+ export default class Mqtt extends DataSource(RectPath(Shape)) {
94
+ private static _image: HTMLImageElement
95
+
96
+ private _client?: mqtt.MqttClient
97
+
98
+ static get image() {
99
+ if (!Mqtt._image) {
100
+ Mqtt._image = new Image()
101
+ Mqtt._image.src = MQTT_IMAGE
102
+ }
103
+
104
+ return Mqtt._image
105
+ }
106
+
107
+ ready() {
108
+ super.ready()
109
+
110
+ if (!this.app.isViewMode) return
111
+
112
+ this._initMqttConnection()
113
+ }
114
+
115
+ _initMqttConnection() {
116
+ try {
117
+ this._client && this._client.end(true, () => {})
118
+ } catch (e) {
119
+ console.error(e)
120
+ }
121
+ delete this._client
122
+
123
+ var {
124
+ broker,
125
+ port = 8441,
126
+ clientId = 'THINGS-FACTORY',
127
+ topic,
128
+ qos = 1,
129
+ retain = false,
130
+ path = '/mqtt',
131
+ dataFormat = 'text',
132
+ user,
133
+ password,
134
+ ssl = false
135
+ } = this.model
136
+
137
+ if (!broker) {
138
+ console.warn('broker not defined')
139
+ return
140
+ }
141
+
142
+ clientId = [clientId, Date.now()].join('-')
143
+
144
+ var client = mqtt.connect(`ws://${broker}:${port}${path}`, {
145
+ keepalive: 10,
146
+ clientId,
147
+ protocolId: 'MQTT',
148
+ protocolVersion: 4,
149
+ clean: true,
150
+ reconnectPeriod: 1000,
151
+ connectTimeout: 30 * 1000,
152
+ will: {
153
+ topic: 'WillMsg',
154
+ payload: 'Connection Closed abnormally..!',
155
+ qos: 0,
156
+ retain: false
157
+ },
158
+ username: user,
159
+ password: password,
160
+ rejectUnauthorized: false
161
+ })
162
+
163
+ client.on('error', err => {
164
+ console.error(err)
165
+ client.end()
166
+ })
167
+
168
+ client.on('connect', packet => {
169
+ console.log('client connected:', clientId, packet)
170
+
171
+ client.subscribe(
172
+ topic,
173
+ {
174
+ qos
175
+ },
176
+ (err, granted) => {
177
+ if (!err) {
178
+ console.error('subscription failed', err)
179
+ } else {
180
+ console.log('mqtt subscription success for topic - ', topic)
181
+ }
182
+ }
183
+ )
184
+ })
185
+
186
+ client.on('message', (topic, message, packet) => {
187
+ this.data = this._convertDataFormat(message.toString(), dataFormat)
188
+ })
189
+
190
+ client.on('close', () => {
191
+ console.log(clientId + ' disconnected')
192
+ })
193
+
194
+ this._client = client
195
+ }
196
+
197
+ dispose() {
198
+ try {
199
+ this._client && this._client.end(true, () => {})
200
+ } catch (e) {
201
+ console.error(e)
202
+ }
203
+ delete this._client
204
+
205
+ super.dispose()
206
+ }
207
+
208
+ _draw(context: CanvasRenderingContext2D): void {
209
+ var { left, top, width, height } = this.bounds
210
+
211
+ context.beginPath()
212
+ this.drawImage(context, Mqtt.image, left, top, width, height)
213
+ }
214
+
215
+ get message() {
216
+ return this.getState('message')
217
+ }
218
+
219
+ set message(message) {
220
+ this.setState('message', message)
221
+ }
222
+
223
+ onchange(after: Properties, before: Properties): void {
224
+ if ('message' in after) {
225
+ const { message } = after
226
+
227
+ if (!this._client || !this._client.connected) {
228
+ return
229
+ }
230
+
231
+ var { topic } = this.state
232
+
233
+ this._client.publish(topic, JSON.stringify(message), {
234
+ qos: 0,
235
+ retain: false
236
+ })
237
+ }
238
+ }
239
+
240
+ get nature() {
241
+ return NATURE
242
+ }
243
+ }
244
+
245
+ Component.register('mqtt', Mqtt)