node-red-contrib-ntrip 0.2.0 → 0.2.2

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/CHANGELOG.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [0.2.2]
5
+ ### Added documentation - [#3](https://github.com/windkh/node-red-contrib-ntrip/issues/3)
6
+
7
+ ## [0.2.1]
8
+ ### Added several auth modes for uploading data to the caster.
9
+ ### added pass through mode - [#10](https://github.com/windkh/node-red-contrib-ntrip/issues/10)
10
+
4
11
  ## [0.2.0]
5
12
  ### Refactored nodes: data can be forwarded to NTRIP caster now.
6
13
 
package/README.md CHANGED
@@ -10,15 +10,6 @@
10
10
  [![Closed Issues](https://img.shields.io/github/issues-closed-raw/windkh/node-red-contrib-ntrip.svg)](https://github.com/windkh/node-red-contrib-ntrip/issues?q=is%3Aissue+is%3Aclosed)
11
11
  ...
12
12
 
13
- This package contains nodes for connecting to a NTRIP server.
14
-
15
- # Dependencies
16
- This package depends on the following libraries
17
- @gnss/nmea
18
- @gnss/rtcm
19
- ntrip-client
20
-
21
-
22
13
  # Thanks for your donation
23
14
  If you want to support this free project. Any help is welcome. You can donate by clicking one of the following links:
24
15
 
@@ -28,22 +19,162 @@ If you want to support this free project. Any help is welcome. You can donate by
28
19
  <a href="https://www.buymeacoffee.com/windka" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>
29
20
 
30
21
 
22
+ This package contains nodes for connecting to a NTRIP server.
23
+
24
+ # Installation
25
+ [![NPM](https://nodei.co/npm/node-red-contrib-ntrip.png?downloads=true)](https://nodei.co/npm/node-red-contrib-ntrip/)
26
+
27
+ You can install the nodes using node-red's "Manage palette" in the side bar.
28
+
29
+ Or run the following command in the root directory of your Node-RED installation
30
+
31
+ npm install node-red-contrib-ntrip --save
32
+
33
+ # Dependencies
34
+ This package depends on the following libraries
35
+ - [@gnss/nmea](https://github.com/node-ntrip/nmea)
36
+ - [@gnss/rtcm](https://github.com/node-ntrip/rtcm)
37
+ - [ntrip-client](https://github.com/dxhbiz/ntrip-client)
38
+
39
+
31
40
  # Credits
32
41
 
42
+ # 👥 Contributors
43
+
44
+ <p align="center">
45
+ <a href="https://github.com/windkh/node-red-contrib-ntrip/graphs/contributors">
46
+ <img src="https://contrib.rocks/image?repo=windkh/node-red-contrib-ntrip" />
47
+ </a>
48
+ </p>
33
49
 
34
50
  # Changelog
35
51
  Changes can be followed [here](/CHANGELOG.md)
36
52
 
37
-
38
53
  # NTRIP Client Node
39
- ...
40
-
54
+ This node connects to a NTRIP caster and can be used in two different modes:
55
+ - upload
56
+ - download
57
+
58
+ ## Download Mode
59
+ ### Configuration
60
+ For downloading data from a NTRIP caster you need to provide the following information
61
+ - __host__ - the IP address or hostname of the NTRIP server (e.g. rtk2go.com)
62
+ - __port__ - the Port number of the NTRIP server (usually this is 2101)
63
+ - __mountpoint__ - the mountpoint of the stream data at the NTRIP server (enter name without /)
64
+
65
+ Depending on the version of the NTRIP caster you need to provide
66
+ - __username__ - the username (e.g. your e-mail address when using rtk2go.com)
67
+ - __password__ - the password (e.g. none)
68
+
69
+ Some NTRIP casters only send data after the client provided its location via a GGA sentence.
70
+ In this case you can provide the X Y Z coordinate here or inject it like illustrated in the example flow
71
+ - __X__ - the X coordinate
72
+ - __Y__ - the Y coordinate
73
+ - __Z__ - the Z coordinate
74
+ - __interval__ - the interval in milliseconds to transmit the location to the NTRIP server.
75
+
76
+ ### Provide Client Location (XYZ) to NTRIP caster
77
+ If you want more control about sending your location to the NTRIP server, then you
78
+ can inject the values as described in the following example:
79
+ ![Alt text](images/SetXYZFlow.png?raw=true "SetXYZ Flow")
80
+
81
+ The function node simply creates an array of X Y Z coordinates in msg.payload.
82
+ Sapos NTRIP casters for example only needs one GGA sentence to initiate streaming.
83
+
84
+ ![Alt text](images/SetXYZFunctionNode.png?raw=true "SetXYZ Function Node")
85
+ See also example flow [**SetXYZ flow**](examples/sapos.json)
86
+
87
+ ## Upload Mode
88
+ ### Configuration
89
+ The configuation properties are the same as described for the download mode.
90
+ You need to provide these additional properties:
91
+ - __Authentication Mode__ - the mode the NTRIP caster accepts.
92
+ - __Pass through data__ - if checked all data is sent to the output for further processing.
93
+
94
+ ### Authentication Modes
95
+ #### Legacy
96
+ This mode initiates the uploading to a mountpoint using plan text.
97
+ ```javascript
98
+ SOURCE ${mountpoint}\r\n\r\n
99
+ ```
100
+ or with password and unsername
101
+ ```javascript
102
+ SOURCE ${password} /${mountpoint}\r\nSource-Agent: NTRIP ${username}\r\n\r\n
103
+ ```
104
+
105
+ #### Legacy (Basic Auth)
106
+ This hybrid mode initiates the uploading to a mountpoint using plan text and Basic Auth.
107
+ ```javascript
108
+ SOURCE ${mountpoint}\r\nAuthorization: Basic ${authorization}\r\n\r\n
109
+ ```
110
+
111
+ #### NTRIP V1
112
+ This mode initiates the uploading to a mountpoint using HTTP with Basic Auth.
113
+ ```javascript
114
+ POST /${mountpoint} HTTP/1.0\r\nUser-Agent: NTRIP ${userAgent}\r\nAuthorization: Basic ${authorization}\r\nContent-Type: gnss/data\r\n\r\n
115
+ ```
116
+
117
+ #### NTRIP V2
118
+ THis mode is equal to NTRIP V1 with some more data.
119
+ ```javascript
120
+ POST /${mountpoint} HTTP/1.1\r\nHost: ${host}:${port}\r\nUser-Agent: NTRIP ${userAgent}\r\nAuthorization: Basic ${authorization}\r\nNtrip-Version: Ntrip/2.0\r\nContent-Type: gnss/data\r\nConnection: keep-alive\r\n\r\n
121
+ ```
41
122
 
42
123
  # RTCM Decoder Node
43
-
124
+ This node accepts binary RTCM data. The node accepts either a single or multiple RTCN messages.
125
+ The converted messages are sent one by one to the output in the following format.
126
+ ```javascript
127
+ msg.payload =
128
+ {
129
+ rtcm, // RTCm message number
130
+ messageType, // a string indicating a readyble RTCM message name
131
+ message, // a structure containing all decoded data
132
+ input, // the raw input message
133
+ };
134
+ ```
44
135
 
45
136
  # NMEA Decoder Node
46
-
137
+ This node accepts binary NMEA data. The node accepts either a single or multiple NMEA messages.
138
+ The converted messages are sent one by one to the output in the following format.
139
+ ```javascript
140
+ msg.payload =
141
+ {
142
+ messageType, // a string indicating a readyble RTCM message name
143
+ message, // a structure containing all decoded data
144
+ input, // the raw input message
145
+ };
146
+ ```
147
+
148
+ # Examples
149
+ Examples are stored in the examples folder an can be imported from within node-red's sidebar via import.
150
+
151
+ ## Download data from NTRIP caster
152
+ Consuming Data is straight forward. Connect to a NTRIP caster, select download mode and
153
+ pass the data to other nodes for further processing: in this example 2 decoder are used.
154
+ The NMEA node is only to show that the stream can be split.
155
+ (It is useless as RTK2Go does not send any NMEA strings)
156
+ See also example flow [**RTK2Go flow**](examples/ntripclient.json)
157
+
158
+ ## Provide XYZ dato to NTRIP caster
159
+ This example is the same as the RTK2Go one except for the fact that Sapos requires sending a GGA sentence
160
+ before transmitting RTCM sentences.
161
+ See also example flow [**Sapos flow**](examples/sapos.json)
162
+
163
+ ## Consume data from TCP source (RTKBase)
164
+ Next to retrieving data from a remote NTRIP caster you can also consume the RTCM stream from a local
165
+ TCP source like a RTKBase Station (e.g. https://github.com/Stefal/rtkbase).
166
+ You can upload the data to any NTRIP caster like Onocoy, Centipede, RTKOnline, ... and use the same data
167
+ on your own. To accomplish this you can use node-red's TCP receiver node.
168
+ You need to activate a TCP server either on your ESP32 XBee or RTKBase.
169
+ See also example flow [**TCP flow**](examples/tcp.json)
170
+
171
+ ## Upload data to NTRIP caster
172
+ Uploading is straight forward, however authentication might be tricky.
173
+ You need to know the mountpoint and credentials before you can initiat an upload.
174
+ Not all NTRIP casters accept the same way of authentication. You can test with
175
+ a local demo version of SNIP by creating a raw TCP input stream.
176
+ (SNIP can be found here https://www.use-snip.com)
177
+ See also example flow [**Upload flow**](examples/upload.json)
47
178
 
48
179
  # License
49
180
 
Binary file
Binary file
@@ -9,6 +9,9 @@
9
9
  defaults: {
10
10
  description: { value:"" },
11
11
  mode: { value: "download", required: true },
12
+ authmode: { value: "legacy", required: true },
13
+ passthrough: { value: false, required: false },
14
+
12
15
  port: { value: 2101, required: false, validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0) && (v <= 65535))) }},
13
16
  host: { value:"" },
14
17
  mountpoint: { value:"" },
@@ -36,11 +39,11 @@
36
39
  var updateMode = function() {
37
40
  var mode = $("#node-input-mode").val();
38
41
  if (mode == "download") {
39
- //$("#coordinates").show();
42
+ $("#uploadoptions").hide();
40
43
  } else if (mode == "upload"){
41
- //$("#coordinates").hide();
44
+ $("#uploadoptions").show();
42
45
  } else {
43
- //$("#coordinates").hide();
46
+ $("#uploadoptions").hide();
44
47
  }
45
48
  };
46
49
  updateMode();
@@ -70,6 +73,23 @@
70
73
  </select>
71
74
  </div>
72
75
 
76
+ <div class="form-row" id="uploadoptions" style="background: var(--red-ui-tertiary-background)">
77
+ <div class="form-row">
78
+ <label for="node-input-authmode"><i class="fa fa-id-card-o"></i> Authentication Mode</label>
79
+ <select id="node-input-authmode" style="width:70%">
80
+ <option value="legacy">Legacy (Plain Text)</option>
81
+ <option value="hybrid">Legacy (Basic Auth)</option>
82
+ <option value="ntripv1">NTRIP V1</option>
83
+ <option value="ntripv2">NTRIP V2</option>
84
+ </select>
85
+ </div>
86
+
87
+ <div class="form-row">
88
+ <label for="node-input-passthrough"><i class="fa fa-long-arrow-right"></i> Pass through data to output.</label>
89
+ <input type="checkbox" id="node-input-passthrough" style="display: inline-block; width: auto; vertical-align: top;">
90
+ </div>
91
+ </div>
92
+
73
93
  <hr align="middle"/>
74
94
 
75
95
  <div class="form-row">
@@ -90,12 +110,6 @@
90
110
  <label for="node-input-password"><i class="fa fa-key"></i> Password</label>
91
111
  <input type="text" id="node-input-password" placeholder="Enter the password here)">
92
112
  </div>
93
-
94
- <div class="form-row">
95
- <label for="node-input-interval"><i class="fa fa-comment"></i> Interval (ms)</label>
96
- <input type="text" id="node-input-interval" placeholder="The interval in milliseconds or 0">
97
- </div>
98
-
99
113
 
100
114
  <hr align="middle"/>
101
115
 
@@ -103,18 +117,23 @@
103
117
  <label style="width: auto"><i class="fa fa-crosshairs"></i> Optional location (if set a NMEA GGA sentence is sent to the server)</label>
104
118
 
105
119
  <div class="form-row">
106
- <label for="node-input-x"> X</label>
107
- <input type="text" id="node-input-x" placeholder="The X position or 0 (optional)">
120
+ <label for="node-input-xcoordinate"> X</label>
121
+ <input type="text" id="node-input-xcoordinate" placeholder="The X position or 0 (optional)">
108
122
  </div>
109
123
 
110
124
  <div class="form-row">
111
- <label for="node-input-y"> Y</label>
112
- <input type="text" id="node-input-y" placeholder="The Y position or 0 (optional)">
125
+ <label for="node-input-ycoordinate"> Y</label>
126
+ <input type="text" id="node-input-ycoordinate" placeholder="The Y position or 0 (optional)">
113
127
  </div>
114
128
 
115
129
  <div class="form-row">
116
- <label for="node-input-z"> Z</label>
117
- <input type="text" id="node-input-z" placeholder="The Z position or 0 (optional)">
130
+ <label for="node-input-zcoordinate"> Z</label>
131
+ <input type="text" id="node-input-zcoordinate" placeholder="The Z position or 0 (optional)">
132
+ </div>
133
+
134
+ <div class="form-row">
135
+ <label for="node-input-interval"><i class="fa fa-comment"></i> Interval (ms)</label>
136
+ <input type="text" id="node-input-interval" placeholder="The interval in milliseconds or 0">
118
137
  </div>
119
138
  </div>
120
139
 
@@ -8,6 +8,7 @@ const net = require('net');
8
8
  class NtripClientUploader extends NtripClient {
9
9
  constructor(options) {
10
10
  super(options);
11
+ this.authmode = options.authmode || 'legacy';
11
12
  }
12
13
 
13
14
  _connect() {
@@ -29,20 +30,38 @@ class NtripClientUploader extends NtripClient {
29
30
  // on connect event
30
31
  this.client.on('connect', () => {
31
32
  const mountpoint = this.mountpoint;
33
+ const userAgent = this.userAgent;
32
34
  const username = this.username;
33
35
  const password = this.password;
34
-
36
+ const host = this.host;
37
+ const port = this.port;
38
+ const authmode = this.authmode;
39
+ const authorization = Buffer.from(
40
+ username + ':' + password,
41
+ 'utf8'
42
+ ).toString('base64');
43
+
35
44
  let data;
36
- if (this.username === '' && this.password === '') {
37
- data = `SOURCE ${mountpoint}\r\n\r\n`;
38
- }
39
- else {
40
- const authorization = Buffer.from(
41
- username + ':' + password,
42
- 'utf8'
43
- ).toString('base64');
44
-
45
- data = `SOURCE ${mountpoint}\r\nAuthorization: Basic ${authorization}\r\n\r\n`;
45
+ switch (authmode) {
46
+ case 'legacy': // Legacy --> rtk2Go accepts this.
47
+ if (username === '' && password === '') {
48
+ data = `SOURCE ${mountpoint}\r\n\r\n`;
49
+ }
50
+ else {
51
+ data = `SOURCE ${password} /${mountpoint}\r\nSource-Agent: NTRIP ${username}\r\n\r\n`;
52
+ }
53
+ break;
54
+ case 'hybrid': // hybrid (legacy + http auth) --> SNIP accepts this.
55
+ data = `SOURCE ${mountpoint}\r\nAuthorization: Basic ${authorization}\r\n\r\n`;
56
+ break;
57
+ case 'ntripv1': // NTRIP V1 POST
58
+ data = `POST /${mountpoint} HTTP/1.0\r\nUser-Agent: NTRIP ${userAgent}\r\nAuthorization: Basic ${authorization}\r\nContent-Type: gnss/data\r\n\r\n`;
59
+ break;
60
+ case 'ntripv2': // NTRIP V2 POST
61
+ data = `POST /${mountpoint} HTTP/1.1\r\nHost: ${host}:${port}\r\nUser-Agent: NTRIP ${userAgent}\r\nAuthorization: Basic ${authorization}\r\nNtrip-Version: Ntrip/2.0\r\nContent-Type: gnss/data\r\nConnection: keep-alive\r\n\r\n`;
62
+ break;
63
+ default:
64
+ throw new Error("Auth mode is not supported " + authmode);
46
65
  }
47
66
 
48
67
  this.client.write(data);
@@ -3,16 +3,20 @@ module.exports = function (RED) {
3
3
 
4
4
  const NtripClient = require("../lib/ntrip-client.js");
5
5
  const NtripServerOkReply = 'ICY 200 OK';
6
+ const NtripServerNotOkReply = 'ICY 406';
6
7
  const NtripServerMissingMountpoint = 'SOURCETABLE 200 OK';
7
8
 
8
9
  function NtripClientNode(config) {
9
10
  RED.nodes.createNode(this, config);
10
11
  let node = this;
11
12
  node.messagesReceived = 0;
13
+ node.passthrough = config.passthrough || false;
14
+
12
15
  let host = config.host;
13
16
  let port = config.port || 2101;
14
17
  let mountpoint = config.mountpoint;
15
- let mode = config.mode || "download";
18
+ let mode = config.mode || 'download';
19
+ let authmode = config.authmode || 'legacy';
16
20
 
17
21
  let client;
18
22
  if(host !== undefined ) {
@@ -27,13 +31,11 @@ module.exports = function (RED) {
27
31
  };
28
32
 
29
33
  // Depending on the caster the clients need to provide the location via GGA sentence.
30
- let x = config.xcoordinate;
31
- let y = config.ycoordinate;
32
- let z = config.zcoordinate;
34
+ let x = parseFloat(config.xcoordinate || 0);
35
+ let y = parseFloat(config.ycoordinate || 0);
36
+ let z = parseFloat(config.zcoordinate || 0);
33
37
 
34
- if (x !== undefined && x !== 0 &&
35
- y !== undefined && y !== 0 &&
36
- z !== undefined && z !== 0) {
38
+ if (x !== 0 && y !== 0 && z !== 0) {
37
39
  options.xyz = [x, y, z];
38
40
  }
39
41
 
@@ -43,6 +45,7 @@ module.exports = function (RED) {
43
45
  }
44
46
  else if (mode === 'upload') {
45
47
  // Uploaders send RTCM data to a mountpoint so that clients can consume it.
48
+ options.authmode = authmode;
46
49
  client = NtripClient.createUploader(options);
47
50
  }
48
51
  else {
@@ -69,6 +72,15 @@ module.exports = function (RED) {
69
72
  shape: 'ring',
70
73
  text: 'NTRIP server connected.',
71
74
  });
75
+ }
76
+ // check if ICY 406 Not Acceptable
77
+ else if (response.startsWith(NtripServerNotOkReply)) {
78
+ node.status({
79
+ fill: 'red',
80
+ shape: 'ring',
81
+ text: 'NTRIP server rejected connection.',
82
+ });
83
+ node.error('Server rejected connect: ' + response);
72
84
  }
73
85
  else if (response.startsWith(NtripServerMissingMountpoint)) {
74
86
  node.status({
@@ -108,6 +120,13 @@ module.exports = function (RED) {
108
120
 
109
121
  this.on('input', async function (msg) {
110
122
  if (msg.payload) {
123
+ node.messagesReceived++;
124
+ node.status({
125
+ fill: 'green',
126
+ shape: 'ring',
127
+ text: 'Messages ' + node.messagesReceived,
128
+ });
129
+
111
130
  try {
112
131
  let data = msg.payload;
113
132
  if (Array.isArray(data)) {
@@ -115,8 +134,11 @@ module.exports = function (RED) {
115
134
  }
116
135
  else {
117
136
  client.write(data);
118
- }
119
137
 
138
+ if(node.passthrough) {
139
+ node.send(msg);
140
+ }
141
+ }
120
142
  } catch (error) {
121
143
  node.status({ fill: 'red', shape: 'ring', text: error });
122
144
  node.error('Failed to write data: ' + error, error);
@@ -27,8 +27,7 @@ module.exports = function (RED) {
27
27
  rtcm : message.messageType,
28
28
  messageType : messageType,
29
29
  message : message,
30
- input : buffer,
31
- length : length
30
+ input : buffer
32
31
  }
33
32
  };
34
33
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-ntrip",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Node for ntrip and rtcm handling.",
5
5
  "node-red": {
6
6
  "version": ">=0.1.0",
@@ -15,7 +15,8 @@
15
15
  "node-red",
16
16
  "rtcm",
17
17
  "ntrip",
18
- "gnss"
18
+ "gnss",
19
+ "mmea"
19
20
  ],
20
21
  "repository": {
21
22
  "type": "git",