mesh-tools 1.0.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 +50 -0
- package/package.json +36 -0
- package/src/index.js +420 -0
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Mesh-Tools
|
|
2
|
+
|
|
3
|
+
This is a packer made for the Meshtastic Project. I am not affiliated with Meshtastic or sponsored. This project is just for fun. [Meshtastic](https://meshtastic.org)
|
|
4
|
+
|
|
5
|
+
## Documentation
|
|
6
|
+
|
|
7
|
+
Here is the table of contents to the documentation;
|
|
8
|
+
|
|
9
|
+
[Table Of Contents](/docs/table-of-contents.md)
|
|
10
|
+
|
|
11
|
+
## What this package does #
|
|
12
|
+
This package is meant to abstract the functions of the meshtastic node.js cli package. It is meant to make the developement of programs that interact with the mesh network easier and more efficient.
|
|
13
|
+
|
|
14
|
+
This is a side project so don't expect this to always be up to date but I'll do my best.
|
|
15
|
+
|
|
16
|
+
It can easily handle connecting to nodes, detecting when someone has dmed you, sending dms, sending on channels, receiving on channels and more. All of the stuff you would ever want.
|
|
17
|
+
|
|
18
|
+
## How it works
|
|
19
|
+
|
|
20
|
+
I tried my best to abstract all of the features that are unnecessary to the average user. The package has been designed around making bots for Meshtastic.
|
|
21
|
+
|
|
22
|
+
Here is all of the code needed to connect to your node. It is much shorter than what would be needed if you were not using my package.
|
|
23
|
+
```js
|
|
24
|
+
// Import the package (not on npm yet)
|
|
25
|
+
const MeshTools = require('mesh-tools')
|
|
26
|
+
// Define the port your node is on over serial
|
|
27
|
+
const node = new MeshTools.SerialNode('/dev/ttyACM1');
|
|
28
|
+
// Connect the node to your computer
|
|
29
|
+
node.connect()
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
If for instance you wanted to listen for direct messages to your node, it is as easy as this chunk of code.
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
// Connect to the receiveDm event
|
|
36
|
+
node.events.on('receiveDm',(data) => {
|
|
37
|
+
// Send a DM back to the sender
|
|
38
|
+
node.sendDirectMessage(`Hello!`,data.from)
|
|
39
|
+
})
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
It's that easy! I'll have more examples later.
|
|
43
|
+
|
|
44
|
+
## Why I made this
|
|
45
|
+
|
|
46
|
+
I made this because I was annoyed at how difficult it was to work with the nodejs cli for Meshtastic. There was little documentation and I frequently ran into issues. To solve these issues, I made this package that bundles all the most common features of the cli into one easy to use package.
|
|
47
|
+
|
|
48
|
+
Thanks for checking this out! Please give it a star :)
|
|
49
|
+
|
|
50
|
+
-JStudios6118
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mesh-tools",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A helpful package for automating the Meshtastic node api",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "Josh Carlson",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"main": "src/index.js",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "node test.js"
|
|
11
|
+
},
|
|
12
|
+
"engines": { "node": ">=18.0.0" },
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@meshtastic/core": "^2.6.7",
|
|
15
|
+
"@meshtastic/transport-http": "^0.2.5",
|
|
16
|
+
"@meshtastic/transport-node": "^0.0.2",
|
|
17
|
+
"@meshtastic/transport-node-serial": "^0.0.2",
|
|
18
|
+
"lowdb": "^7.0.1"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"meshtastic",
|
|
22
|
+
"mesh",
|
|
23
|
+
"iot",
|
|
24
|
+
"lora",
|
|
25
|
+
"radio",
|
|
26
|
+
"bot"
|
|
27
|
+
],
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/JStudios6118/Mesh-Tools"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/JStudios6118/Mesh-Tools#readme",
|
|
33
|
+
"bugs": "https://github.com/JStudios6118/Mesh-Tools/issues",
|
|
34
|
+
"files": ["src"]
|
|
35
|
+
|
|
36
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
const { MeshDevice, Protobuf } = require("@meshtastic/core");
|
|
2
|
+
const { TransportNodeSerial } = require("@meshtastic/transport-node-serial");
|
|
3
|
+
const { TransportHTTP } = require("@meshtastic/transport-http");
|
|
4
|
+
const { TransportNode } = require("@meshtastic/transport-node");
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const { EventEmitter } = require('events');
|
|
8
|
+
const { JSONFilePreset } = require("lowdb/node");
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
//Logger.setLogLevel(LogLevel.NONE)
|
|
12
|
+
|
|
13
|
+
// Base class for all nodes (connected to host device)
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
|
|
17
|
+
TODO:
|
|
18
|
+
-ADD MESSAGE ACKNOWLEDGEMENT HANDLING
|
|
19
|
+
-ADD TCP AND HTTP CONNECTION TYPES
|
|
20
|
+
-MAKE EVERYTHING ASYNCHRONOUS
|
|
21
|
+
-ADD LOG LEVELS
|
|
22
|
+
-ADD SUPPORT FOR DIFFERENT PACKET TYPES LIKE TELEMETRY AND ETC
|
|
23
|
+
-ADD PROPER JSDOC DOCUMENTATION FOR AUTOFILL AND SUCH
|
|
24
|
+
|
|
25
|
+
DONE:
|
|
26
|
+
-ADD BROADCAST MESSAGING
|
|
27
|
+
-ADD A NODE DATABASE BUILDER
|
|
28
|
+
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
// Some settings. Will add more later.
|
|
32
|
+
settings = {
|
|
33
|
+
print_logs: true
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// A configure function to change global settings.
|
|
37
|
+
function Configure(property, value){
|
|
38
|
+
settings[property] = value
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Simple Logger class to provide nice looking, customizable logs
|
|
42
|
+
class Logger {
|
|
43
|
+
#name;
|
|
44
|
+
|
|
45
|
+
// Sets the name that will show up before a message to help identify where the message is coming from.
|
|
46
|
+
constructor(name){
|
|
47
|
+
this.#name = name;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
log(message){
|
|
51
|
+
if (!settings.print_logs){
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
console.log(`[MT] ${this.#name} | ${message}`)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
class NodeDB {
|
|
59
|
+
|
|
60
|
+
// In the following functions, please note that the identifier fields can take in either the nodes number or id.
|
|
61
|
+
|
|
62
|
+
#logger = new Logger('[Node DB]')
|
|
63
|
+
|
|
64
|
+
#db = null;
|
|
65
|
+
#dbData;
|
|
66
|
+
|
|
67
|
+
// Initialize the database file
|
|
68
|
+
async init(databasePath){
|
|
69
|
+
if (this.#db!=null){ this.#logger.log("Database Already Initialized. Skipping..."); return false }
|
|
70
|
+
|
|
71
|
+
this.#db = await JSONFilePreset(path.join(databasePath,'nodeDb.json'), { nodes: [] });
|
|
72
|
+
this.#dbData = this.#db.data;
|
|
73
|
+
await this.#db.write();
|
|
74
|
+
return true
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Internal method to check if an node of an id exists and return its index.
|
|
78
|
+
#checkId(input){
|
|
79
|
+
//this.#logger.log(`IN: ${input}`)
|
|
80
|
+
if (typeof input === "number"){
|
|
81
|
+
return this.#dbData.nodes.findIndex(p => p.number === input)
|
|
82
|
+
} else if (typeof input === "string"){
|
|
83
|
+
return this.#dbData.nodes.findIndex(p => p.id === input)
|
|
84
|
+
} else {
|
|
85
|
+
throw new Error('.nodeExists: Invalid type! Must be either a string or number.');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Internal command that returns a node from the database based on the id. Not compatible with node number.
|
|
90
|
+
#getNodeIndexById(identifier){
|
|
91
|
+
if (this.#db===null){ this.#logger.log("Database has not been initialized yet!"); return false }
|
|
92
|
+
return this.#dbData.nodes.findIndex(p => p.id === identifier);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Returns a bool on whether or not a node of the id exists.
|
|
96
|
+
nodeExists(identifier){
|
|
97
|
+
if (this.#db===null){ this.#logger.log("Database has not been initialized yet!"); return false }
|
|
98
|
+
//console.log(typeof identifier)
|
|
99
|
+
const index = this.#checkId(identifier)
|
|
100
|
+
if (index===-1){
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
return true;
|
|
104
|
+
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Gets a desired node using the identifier
|
|
108
|
+
getNode(identifier){
|
|
109
|
+
if (this.#db===null){ this.#logger.log("Database has not been initialized yet!"); return false }
|
|
110
|
+
const index = this.#checkId(identifier)
|
|
111
|
+
if (index===-1){
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//this.#logger.log(`Index of Node: ${index}`)
|
|
116
|
+
|
|
117
|
+
const { longName, shortName, id, number, storedData } = this.#dbData.nodes[index];
|
|
118
|
+
|
|
119
|
+
return new Node(longName,shortName,id,number,storedData);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Add a node to the database. If the node is already present, update its lastheard value and validate other data. Does not affect stored data.
|
|
123
|
+
async push(node){
|
|
124
|
+
//console.log('pushing node:', node.id, 'number:', node.number)
|
|
125
|
+
if (this.#db===null){ this.#logger.log("Database has not been initialized yet!"); return false }
|
|
126
|
+
if (this.nodeExists(node.id)){
|
|
127
|
+
let nodeData = this.getNode(node.id)
|
|
128
|
+
this.#dbData.nodes[this.#getNodeIndexById(node.id)] = {
|
|
129
|
+
...nodeData.info,
|
|
130
|
+
id:node.id,
|
|
131
|
+
number:node.number,
|
|
132
|
+
longName:node.longName,
|
|
133
|
+
shortName:node.shortName,
|
|
134
|
+
lastHeard: Math.floor(Date.now() / 1000)
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
//console.log(node.info())
|
|
138
|
+
this.#dbData.nodes.push(node.info)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
//console.log("Succeeded!")
|
|
142
|
+
|
|
143
|
+
await this.#db.write();
|
|
144
|
+
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Gets the data on a desired node as defined by the identifier
|
|
149
|
+
async getNodeStoredData(identifier){
|
|
150
|
+
if (this.#db===null){ this.#logger.log("Database has not been initialized yet!"); return false }
|
|
151
|
+
|
|
152
|
+
const index = this.#checkId(identifier)
|
|
153
|
+
if (index===-1){
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
//this.#logger.log(`All Node Data: ${JSON.stringify(this.getNode(identifier),null,2)}`)
|
|
158
|
+
|
|
159
|
+
return this.getNode(identifier).storedData;
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Update the custom stored data in the node as defined by the identifier
|
|
165
|
+
async updateStoredData(identifier, data) {
|
|
166
|
+
if (this.#db === null) { this.#logger.log("Database has not been initialized yet!"); return false }
|
|
167
|
+
|
|
168
|
+
const index = this.#checkId(identifier);
|
|
169
|
+
if (index === -1) { this.#logger.log("Node not found!"); return false }
|
|
170
|
+
|
|
171
|
+
this.#dbData.nodes[index].storedData = {
|
|
172
|
+
...this.#dbData.nodes[index].storedData,
|
|
173
|
+
...data
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
await this.#db.write();
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Node class for NodeDB
|
|
183
|
+
class Node {
|
|
184
|
+
constructor(longName,shortName,id,number,storedData){
|
|
185
|
+
this.longName = longName;
|
|
186
|
+
this.shortName = shortName;
|
|
187
|
+
this.id = id;
|
|
188
|
+
this.number = number;
|
|
189
|
+
this.lastHeard = Math.floor(Date.now() / 1000); // Set lastHeard time to current epoch time
|
|
190
|
+
this.storedData = storedData || {};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Returns all data on Node as a JSON object.
|
|
194
|
+
get info(){
|
|
195
|
+
return {
|
|
196
|
+
longName:this.longName,
|
|
197
|
+
shortName:this.shortName,
|
|
198
|
+
id:this.id,
|
|
199
|
+
number:this.number,
|
|
200
|
+
lastHeard:this.lastHeard,
|
|
201
|
+
storedData:this.storedData
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// The base device class for all Meshtastic node connections. Houses all main logic and code for handling packets events and more.
|
|
208
|
+
class Device {
|
|
209
|
+
|
|
210
|
+
#device = null; // Mesh device. When set to null, many command will not run
|
|
211
|
+
#ownId = null; // Id of connected node
|
|
212
|
+
#longName;
|
|
213
|
+
#shortName;
|
|
214
|
+
|
|
215
|
+
// Creates an empty db class. Does nothing by itself, needs to be activated. I didn't leave it empty for autofill reaons and my sanity.
|
|
216
|
+
db = new NodeDB();
|
|
217
|
+
|
|
218
|
+
//#pendingMessages = new Map();
|
|
219
|
+
|
|
220
|
+
// Creates a variable that developers can listen for events on.
|
|
221
|
+
events = new EventEmitter();
|
|
222
|
+
|
|
223
|
+
get ownId(){ return this.#ownId } // Getter for grabbing the devices own id number.
|
|
224
|
+
|
|
225
|
+
// Constructor called by extended class
|
|
226
|
+
constructor(){
|
|
227
|
+
this.logger = new Logger("Mesh Device");
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Connect super script. Uses transport to init a MeshDevice.
|
|
231
|
+
async connect(transport){
|
|
232
|
+
|
|
233
|
+
this.logger.log('Connecting Node...')
|
|
234
|
+
|
|
235
|
+
if (transport.port?.flush) {
|
|
236
|
+
this.logger.log('Flushing Transport')
|
|
237
|
+
await transport.port.flush();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
this.#device = new MeshDevice(transport);
|
|
241
|
+
this.#device.log.settings.minLevel = 5;
|
|
242
|
+
|
|
243
|
+
// wait for the configured event instead of awaiting configure()
|
|
244
|
+
await new Promise((resolve, reject) => {
|
|
245
|
+
this.#device.events.onDeviceStatus.subscribe((status) => {
|
|
246
|
+
if (status === 7) resolve() // 7 = DeviceConfigured
|
|
247
|
+
if (status === 9) reject(new Error("Device disconnected during config"))
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
this.#device.configure().catch(reject)
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
this.logger.log('Device Successfully Configured!')
|
|
254
|
+
|
|
255
|
+
//console.log(this.#device)
|
|
256
|
+
|
|
257
|
+
// Save nodes id. Useful for handling dms
|
|
258
|
+
this.#ownId = this.#device.myNodeInfo.myNodeNum;
|
|
259
|
+
|
|
260
|
+
// Add an event listerner for ownNodeInfo to get the nodes own information
|
|
261
|
+
this.#setupListeners();
|
|
262
|
+
|
|
263
|
+
this.events.emit('connected', {ownId:this.#ownId});
|
|
264
|
+
|
|
265
|
+
return {ownId:this.#ownId}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Starts and configures the Node Database.
|
|
269
|
+
async startNodeDB(databasePath){
|
|
270
|
+
this.db = new NodeDB();
|
|
271
|
+
await this.db.init(databasePath);
|
|
272
|
+
|
|
273
|
+
this.logger.log('Started Database!')
|
|
274
|
+
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Setup listeners for different Meshtastic events
|
|
279
|
+
#setupListeners() {
|
|
280
|
+
// Not sure if this does anything. Needs more testing
|
|
281
|
+
this.#device.events.onNodeInfoPacket.subscribe((nodeInfo) => {
|
|
282
|
+
if (nodeInfo.num === this.#ownId) {
|
|
283
|
+
this.#longName = nodeInfo.user.longName;
|
|
284
|
+
this.#shortName = nodeInfo.user.shortName;
|
|
285
|
+
this.events.emit('ownNameReceived', { longName: this.#longName, shortName:this.#shortName });
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// Unused for now
|
|
290
|
+
this.#device.events.onMeshPacket.subscribe((packet) => {
|
|
291
|
+
if (packet.from === 2996808676){
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// Triggers when the node receives info about another node (name,location,etc)
|
|
296
|
+
this.#device.events.onUserPacket.subscribe((packet) => {
|
|
297
|
+
const dat = packet.data
|
|
298
|
+
const data = {longName:dat.longName, shortName:dat.shortName, id:dat.id, number:packet.from}
|
|
299
|
+
//console.log(`NODEINFO: ${JSON.stringify(packet,null,2)}`)
|
|
300
|
+
const nodeInfo = new Node(data.longName,data.shortName,data.id,data.number);
|
|
301
|
+
this.events.emit("nodeInfoReceived", nodeInfo);
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
// Triggers when a message is received. Handles packet type.
|
|
305
|
+
this.#device.events.onMessagePacket.subscribe((packet) => {
|
|
306
|
+
if (packet.to === this.#ownId && packet.type === 'direct'){
|
|
307
|
+
this.events.emit('receiveDm',packet)
|
|
308
|
+
} else if (packet.type === 'broadcast') {
|
|
309
|
+
this.events.emit('receiveMessage',packet)
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Send a message in a channel
|
|
317
|
+
async sendMessage(message,channel){
|
|
318
|
+
const id = await this.#device.sendText(message,0xFFFFFFFF,true,channel);
|
|
319
|
+
return id
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Send a message in a channel as a reply.
|
|
323
|
+
async sendReplyMessage(message,channel,replyId){
|
|
324
|
+
const id = await this.#device.sendText(message,0xFFFFFFFF,true,channel,replyId);
|
|
325
|
+
return id
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Send a direct message to another node.
|
|
329
|
+
async sendDirectMessage(message,to){
|
|
330
|
+
const id = await this.#device.sendText(message,to);
|
|
331
|
+
return id
|
|
332
|
+
//this.logger.log(`PACKER ID: ${id}`)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Send a direct message to another node as a reply.
|
|
336
|
+
async sendReplyDirectMessage(message,to,replyId){
|
|
337
|
+
const id = await this.#device.sendText(message,to,true,null,replyId);
|
|
338
|
+
return id
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Constructor for Mesh Nodes connected to host over serial
|
|
344
|
+
class SerialNode extends Device {
|
|
345
|
+
|
|
346
|
+
#serial_address;
|
|
347
|
+
|
|
348
|
+
constructor(serial_address){
|
|
349
|
+
super();
|
|
350
|
+
this.#serial_address = serial_address;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
async connect() {
|
|
354
|
+
if (this.device != null) {
|
|
355
|
+
this.logger.log("Device is already connected! Skipping...");
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
this.logger.log("Creating Transport...")
|
|
360
|
+
|
|
361
|
+
const transport = await TransportNodeSerial.create(this.#serial_address);
|
|
362
|
+
return await super.connect(transport);
|
|
363
|
+
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Constructor for Mesh Node connected to host over TCP
|
|
369
|
+
// Untested
|
|
370
|
+
class TCPNode extends Device {
|
|
371
|
+
|
|
372
|
+
#tcp_ip_address;
|
|
373
|
+
|
|
374
|
+
constructor(tcp_ip_address){
|
|
375
|
+
super();
|
|
376
|
+
this.#tcp_ip_address = tcp_ip_address;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
async connect() {
|
|
380
|
+
if (this.device != null) {
|
|
381
|
+
this.logger.log("Device is already connected! Skipping...");
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
this.logger.log("Creating Transport...")
|
|
386
|
+
|
|
387
|
+
const transport = await TransportNode.create(this.#tcp_ip_address);
|
|
388
|
+
return await super.connect(transport);
|
|
389
|
+
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Constructor for Mesh Node connected to host over HTTP
|
|
395
|
+
// Untested
|
|
396
|
+
class HTTPNode extends Device {
|
|
397
|
+
|
|
398
|
+
#http_ip_address;
|
|
399
|
+
|
|
400
|
+
constructor(http_ip_address){
|
|
401
|
+
super();
|
|
402
|
+
this.#http_ip_address = http_ip_address;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
async connect() {
|
|
406
|
+
if (this.device != null) {
|
|
407
|
+
this.logger.log("Device is already connected! Skipping...");
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
this.logger.log("Creating Transport...")
|
|
412
|
+
|
|
413
|
+
const transport = await TransportHTTP.create(this.#http_ip_address);
|
|
414
|
+
return await super.connect(transport);
|
|
415
|
+
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
module.exports = { SerialNode, TCPNode, HTTPNode, Configure }
|