├── .npm
└── package
│ ├── .gitignore
│ ├── README
│ └── npm-shrinkwrap.json
├── .versions
├── README.md
├── lib
├── mqtt.js
└── mqtt_collection.js
├── package.js
└── smart.json
/.npm/package/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.npm/package/README:
--------------------------------------------------------------------------------
1 | This directory and the files immediately inside it are automatically generated
2 | when you change this package's NPM dependencies. Commit the files in this
3 | directory (npm-shrinkwrap.json, .gitignore, and this README) to source control
4 | so that others run the same versions of sub-dependencies.
5 |
6 | You should NOT check in the node_modules directory that Meteor automatically
7 | creates; if you are using git, the .gitignore file tells git to ignore it.
8 |
--------------------------------------------------------------------------------
/.npm/package/npm-shrinkwrap.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "mqtt": {
4 | "version": "1.2.0",
5 | "dependencies": {
6 | "commist": {
7 | "version": "1.0.0",
8 | "dependencies": {
9 | "leven": {
10 | "version": "1.0.2"
11 | }
12 | }
13 | },
14 | "concat-stream": {
15 | "version": "1.4.8",
16 | "dependencies": {
17 | "typedarray": {
18 | "version": "0.0.6"
19 | },
20 | "readable-stream": {
21 | "version": "1.1.13",
22 | "dependencies": {
23 | "core-util-is": {
24 | "version": "1.0.1"
25 | },
26 | "isarray": {
27 | "version": "0.0.1"
28 | },
29 | "string_decoder": {
30 | "version": "0.10.31"
31 | }
32 | }
33 | }
34 | }
35 | },
36 | "end-of-stream": {
37 | "version": "1.1.0",
38 | "dependencies": {
39 | "once": {
40 | "version": "1.3.2",
41 | "dependencies": {
42 | "wrappy": {
43 | "version": "1.0.1"
44 | }
45 | }
46 | }
47 | }
48 | },
49 | "help-me": {
50 | "version": "0.1.0",
51 | "dependencies": {
52 | "pump": {
53 | "version": "1.0.0",
54 | "dependencies": {
55 | "once": {
56 | "version": "1.3.2",
57 | "dependencies": {
58 | "wrappy": {
59 | "version": "1.0.1"
60 | }
61 | }
62 | }
63 | }
64 | }
65 | }
66 | },
67 | "inherits": {
68 | "version": "2.0.1"
69 | },
70 | "minimist": {
71 | "version": "1.1.1"
72 | },
73 | "mqtt-connection": {
74 | "version": "2.1.1",
75 | "dependencies": {
76 | "reduplexer": {
77 | "version": "1.1.0"
78 | },
79 | "through2": {
80 | "version": "0.6.5"
81 | }
82 | }
83 | },
84 | "mqtt-packet": {
85 | "version": "3.2.0",
86 | "dependencies": {
87 | "bl": {
88 | "version": "0.9.4"
89 | }
90 | }
91 | },
92 | "readable-stream": {
93 | "version": "1.0.33",
94 | "dependencies": {
95 | "core-util-is": {
96 | "version": "1.0.1"
97 | },
98 | "isarray": {
99 | "version": "0.0.1"
100 | },
101 | "string_decoder": {
102 | "version": "0.10.31"
103 | }
104 | }
105 | },
106 | "websocket-stream": {
107 | "version": "1.5.0",
108 | "dependencies": {
109 | "duplexify": {
110 | "version": "3.4.0",
111 | "dependencies": {
112 | "end-of-stream": {
113 | "version": "1.0.0",
114 | "dependencies": {
115 | "once": {
116 | "version": "1.3.2",
117 | "dependencies": {
118 | "wrappy": {
119 | "version": "1.0.1"
120 | }
121 | }
122 | }
123 | }
124 | },
125 | "readable-stream": {
126 | "version": "1.1.13",
127 | "dependencies": {
128 | "core-util-is": {
129 | "version": "1.0.1"
130 | },
131 | "isarray": {
132 | "version": "0.0.1"
133 | },
134 | "string_decoder": {
135 | "version": "0.10.31"
136 | }
137 | }
138 | }
139 | }
140 | },
141 | "through2": {
142 | "version": "0.6.5"
143 | },
144 | "ws": {
145 | "version": "0.7.2",
146 | "dependencies": {
147 | "options": {
148 | "version": "0.0.6"
149 | },
150 | "ultron": {
151 | "version": "1.0.1"
152 | },
153 | "bufferutil": {
154 | "version": "1.1.0",
155 | "dependencies": {
156 | "bindings": {
157 | "version": "1.2.1"
158 | },
159 | "nan": {
160 | "version": "1.8.4"
161 | }
162 | }
163 | },
164 | "utf-8-validate": {
165 | "version": "1.1.0",
166 | "dependencies": {
167 | "bindings": {
168 | "version": "1.2.1"
169 | },
170 | "nan": {
171 | "version": "1.8.4"
172 | }
173 | }
174 | }
175 | }
176 | }
177 | }
178 | },
179 | "xtend": {
180 | "version": "4.0.0"
181 | }
182 | }
183 | }
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/.versions:
--------------------------------------------------------------------------------
1 | meteor@1.1.6
2 | perak:mqtt-collection@1.0.3
3 | underscore@1.0.3
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | mqtt-collection package for Meteor
2 | ==================================
3 |
4 | - Messages received via MQTT broker are written into collection
5 |
6 | - Data inserted into collection is broadcasted via MQTT
7 |
8 |
9 | Example
10 | -------
11 |
12 | ### Connect to MQTT broker and subscribe to topic (server side only)
13 |
14 | ```
15 | MyCollection.mqttConnect("mqtt://test.mosquitto.org", ["presence"], {}, {});
16 | ```
17 |
18 | We are now connected and subscribed to "presence" topic. Anything published to "presence" MQTT topic will be written into MyCollection.
19 |
20 |
21 | ### Broadcast data (works both on client and server)
22 |
23 | ```
24 | MyCollection.insert({ topic: "presence", message: "Hello world! :)", broadcast: true });
25 | ```
26 |
27 | You need to insert three **mandatory** fields: `topic`, `message` and `broadcast` and your message will be broadcasted via MQTT broker to specified topic.
28 |
29 |
30 | Functions
31 | =========
32 |
33 | Collection.mqttConnect(uri, topics, options, mqttOptions)
34 | --------------------------------------------
35 |
36 | Establishes connection to MQTT broker and subscribes to listed topic(s).
37 |
38 | **Arguments:**
39 |
40 | - `uri` is mqtt broker address
41 | - `topics` is array of strings or single string - topic name(s) to subscribe on connect
42 | - `options` is object with following properties:
43 | ```
44 | {
45 | insert: false,
46 | raw: false
47 | }
48 | ```
49 | - `insert` - if set to true, each message will be inserted into collection (and your collection will grow!). If this option is not set (or set to false) messages will be upsert-ed (you'l have single document for each topic). Default: false
50 | - `raw` - if set to true, received string will be written as-is. If this option is not set (or set to false) received string will be converted to object with `JSON.parse()`. Default: false
51 | - `mqttOptions` is an object that is supplied to `mqtt.connect([url],options)` in the MQTT.js library for configuring the underlying options of the MQTT.js-client. See the docs.
52 |
53 | Collection.mqttDisconnect()
54 | ---------------------------
55 |
56 | Closes connection to MQTT broker
57 |
58 |
59 | Collection.mqttSubscribe(topics)
60 | --------------------------------
61 |
62 | Subscribe to specified topic(s). Works only **after** MQTT connection is established.
63 |
64 | **Arguments:**
65 |
66 | - `topics` is array of strings or single string - topic name(s) to subscribe
67 |
68 |
69 | Live example
70 | ============
71 |
72 | You can find example application using this package here.
73 |
74 |
75 | That's all folks :)
76 |
--------------------------------------------------------------------------------
/lib/mqtt.js:
--------------------------------------------------------------------------------
1 | mqtt = Npm.require('mqtt');
--------------------------------------------------------------------------------
/lib/mqtt_collection.js:
--------------------------------------------------------------------------------
1 | var Fiber = Npm.require("fibers");
2 |
3 | var Mongo = Package.mongo.Mongo;
4 |
5 | Mongo.Collection.prototype.mqttConnect = function(uri, topics, options, mqttOptions) {
6 | var self = this;
7 | this.mqttDisconnect();
8 |
9 | this.options = options || {};
10 | this.mqttOptions = mqttOptions || {};
11 |
12 | this._mqttClient = mqtt.connect(uri,self.mqttOptions);
13 |
14 | this._mqttClient.on("connect", function() {
15 | self.mqttSubscribe(topics);
16 | });
17 |
18 | this._mqttClient.on("message", function(topic, message) {
19 | var msg = message.toString();
20 | if(!self.options.raw) {
21 | try {
22 | msg = JSON.parse(msg);
23 | } catch(e) {
24 | }
25 | }
26 |
27 | Fiber(function() {
28 |
29 | if(self.options.insert) {
30 | self.insert({
31 | topic: topic,
32 | message: msg
33 | }, function(e, r) {
34 | if(e) {
35 | console.log(e);
36 | } else {
37 | if(self.options.insertLimit) {
38 | var insertLimit = parseInt(self.options.insertLimit);
39 | if(!isNaN(insertLimit)) {
40 | while(self.find({ topic: topic }).count() > insertLimit) {
41 | var removeId = self.findOne({ topic: topic }, { sort: [["createdAt", "asc"]] });
42 | if(removeId) {
43 | self.remove({ _id: removeId._id });
44 | }
45 | }
46 | }
47 | }
48 | }
49 | });
50 | } else {
51 | self.upsert(
52 | {
53 | topic: topic
54 | },
55 | {
56 | $set: {
57 | topic: topic,
58 | message: msg
59 | }
60 | },
61 | {
62 | },
63 | function(e, r) {
64 | if(e) console.log(e);
65 | });
66 | }
67 | }).run();
68 | });
69 |
70 | var init = true;
71 | this.find().observeChanges({
72 | added: function(id, doc) {
73 | if(!init) {
74 | if(doc && doc.topic && doc.message && doc.broadcast && self._mqttClient) {
75 | var msg = typeof doc.message === 'object' ? JSON.stringify(doc.message) : doc.message + "";
76 | self.remove({ _id: id });
77 | self._mqttClient.publish(doc.topic, msg);
78 | }
79 | }
80 | }
81 | });
82 | init = false;
83 | };
84 |
85 | Mongo.Collection.prototype.mqttDisconnect = function() {
86 | if(this._mqttClient) this._mqttClient.end();
87 | this._mqttClient = null;
88 | };
89 |
90 | Mongo.Collection.prototype.mqttSubscribe = function(topics) {
91 | var self = this;
92 | if(!this._mqttClient) return;
93 | if(!topics) return;
94 |
95 | if(typeof topics == "string" || topics instanceof String) {
96 | this._mqttClient.subscribe(topics);
97 | } else if(_.isArray(topics)) {
98 | _.each(topics, function(topic) {
99 | self._mqttClient.subscribe(topic);
100 | });
101 | }
102 | };
--------------------------------------------------------------------------------
/package.js:
--------------------------------------------------------------------------------
1 | Package.describe({
2 | name: "perak:mqtt-collection",
3 | version: "1.0.5",
4 | summary: "IoT for Meteor - send/receive MQTT messages via collections",
5 | git: "https://github.com/perak/meteor-mqtt-collection.git",
6 | documentation: "README.md"
7 | });
8 |
9 | Npm.depends({
10 | "mqtt": "1.13.0"
11 | });
12 |
13 | Package.onUse(function(api) {
14 | api.versionsFrom("1.0");
15 | api.addFiles("lib/mqtt.js", "server");
16 | api.addFiles("lib/mqtt_collection.js", "server");
17 | api.export("mqtt");
18 | });
19 |
--------------------------------------------------------------------------------
/smart.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mqtt",
3 | "description": "IoT - send/receive MQTT messages via collections",
4 | "homepage": "https://github.com/perak/meteor-mqtt-collection",
5 | "author": "Petar Korponaic",
6 | "version": "1.0.5",
7 | "git": "https://github.com/perak/meteor-mqtt-collection.git",
8 | "packages": {}
9 | }
10 |
--------------------------------------------------------------------------------