node-red-contrib-tak-registration 0.1.2 → 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.
@@ -1,3 +1,4 @@
1
+ const { methodToString } = require('adm-zip/util');
1
2
 
2
3
  module.exports = function(RED) {
3
4
  "use strict";
@@ -8,12 +9,16 @@ module.exports = function(RED) {
8
9
  const FormData = require('form-data')
9
10
  const { v4: uuidv4 } = require('uuid');
10
11
  const uuid = require('uuid');
12
+ const ver = require('./package.json').version;
11
13
 
12
14
  function TakRegistrationNode(n) {
13
15
  RED.nodes.createNode(this,n);
14
16
  this.group = n.group;
17
+ this.role = n.role || "Gateway";
18
+ this.type = n.type || "a-f-G-I-B";
15
19
  this.lat = n.latitude;
16
20
  this.lon = n.longitude;
21
+ this.alt = 9999999;
17
22
  this.callsign = n.callsign;
18
23
  this.repeat = n.repeat;
19
24
  this.host = n.dphost;
@@ -31,8 +36,11 @@ module.exports = function(RED) {
31
36
  etime: new Date(Date.now() + 2000 * node.repeat).toISOString(),
32
37
  lat: node.lat,
33
38
  lon: node.lon,
39
+ alt: node.alt,
34
40
  callsign: node.callsign,
35
41
  group: node.group,
42
+ role: node.role,
43
+ type: node.type,
36
44
  heartbeat: true
37
45
  });
38
46
  };
@@ -46,13 +54,13 @@ module.exports = function(RED) {
46
54
  };
47
55
 
48
56
  node.repeaterSetup();
49
- setTimeout(sendIt, 2000);
57
+ setTimeout(sendIt, 2500);
50
58
 
51
- this.on("input",function(msg) {
59
+ node.on("input",function(msg) {
52
60
  if (msg.heartbeat) { // Register gateway and do the heartbeats
53
- var template = `<event version="2.0" uid="${node.uuid}" type="a-f-G-I-B" how="h-e" time="${msg.time}" start="${msg.time}" stale="${msg.etime}"><point lat="${msg.lat}" lon="${msg.lon}" hae="9999999" ce="9999999" le="9999999"/><detail><takv os="${os.platform()}" version="4.1.0.231" device="${os.hostname()}" platform="ATAK-CIV"/><contact endpoint="*:-1:stcp" callsign="${msg.callsign}"/><uid Droid="${msg.callsign}"/><__group name="${msg.group}" role="Gateway"/><status battery="99"/></detail></event>`;
61
+ var template = `<event version="2.0" uid="${node.uuid}" type="${msg.type}" how="h-e" time="${msg.time}" start="${msg.time}" stale="${msg.etime}"><point lat="${msg.lat}" lon="${msg.lon}" hae="${msg.alt}" ce="9999999" le="9999999"/><detail><takv device="${os.hostname()}" os="${os.platform()}" platform="NRedTAK" version="${ver}"/><contact endpoint="*:-1:stcp" callsign="${msg.callsign}"/><uid Droid="${msg.callsign}"/><__group name="${msg.group}" role="${msg.role}"/><status battery="99"/></detail></event>`;
54
62
  node.send({payload:template});
55
- node.status({fill:"green", shape:"dot", text: node.repeat/1000+"s - "+node.callsign});
63
+ node.status({fill:"green", shape:"dot", text:node.repeat/1000+"s - "+node.callsign});
56
64
  return;
57
65
  }
58
66
  // If there are attachments handle them first.
@@ -146,17 +154,69 @@ module.exports = function(RED) {
146
154
  node.error(error.message,error);
147
155
  })
148
156
  }
149
- else if (typeof msg.payload === "string") { // Assume it's proper XML event so pass straight through
150
- if (msg.payload.trim().startsWith('<') && msg.payload.trim().endsWith('>')) {
157
+ else if (typeof msg.payload === "string" ) {
158
+ if (msg.payload.trim().startsWith('<') && msg.payload.trim().endsWith('>')) { // Assume it's proper XML event so pass straight through
151
159
  node.send(msg);
152
160
  }
161
+ else if (msg.payload.trim().startsWith('$GPGGA')) { // maybe it's an NMEA string
162
+ // console.log("It's NMEA",msg.payload);
163
+ var nm = msg.payload.trim().split(',');
164
+ if (nm[0] === '$GPGGA' && nm[6] > 0) {
165
+ const la = parseInt(nm[2].substr(0,2)) + parseFloat(nm[2].substr(2))/60;
166
+ node.lat = ((nm[3] === "N") ? la : -la).toFixed(6);
167
+ const lo = parseInt(nm[4].substr(0,3)) + parseFloat(nm[4].substr(3))/60;
168
+ node.lon = ((nm[5] === "E") ? lo : -lo).toFixed(6);
169
+ node.alt = nm[9];
170
+ }
171
+ }
172
+ }
173
+ // Handle a generic worldmap marker style as a normal marker
174
+ else if (typeof msg.payload === "object" && msg.payload.hasOwnProperty("name") && msg.payload.hasOwnProperty("lat") && msg.payload.hasOwnProperty("lon")) {
175
+ var d = new Date();
176
+ var st = d.toISOString();
177
+ var ttl = ((msg.payload.ttl || 0) * 1000) || 60000;
178
+ var et = Date.now() + ttl;
179
+ et = (new Date(et)).toISOString();
180
+ var tag = msg.payload.remarks || "";
181
+ if (msg.payload.tag) { tag += " " + msg.payload.tag }
182
+ if (msg.payload.layer) { tag += " #" + msg.payload.layer }
183
+ else { tag += " #Worldmap"; }
184
+ var type = msg.payload.cottype || "a-u-g-u";
185
+ if (!msg.payload.cottype && !msg.payload.SIDC && msg.payload.aistype) {
186
+ msg.payload.SIDC = ais2sidc(msg.payload.aistype);
187
+ }
188
+ if (!msg.payload.cottype && msg.payload.SIDC) {
189
+ var s = msg.payload.SIDC.split('-')[0].toLowerCase();
190
+ if (s.startsWith('s')) {
191
+ type = s.split('').join('-').replace('s-','a-').replace('-p-','-');
192
+ }
193
+ }
194
+ // console.log("TYPE",type)
195
+ msg.payload = `<event version="2.0" type="${type}" uid="${msg.payload.name}" time="${st}" start="${st}" stale="${et}" how="h-e">
196
+ <point lat="${msg.payload.lat || 0}" lon="${msg.payload.lon || 0}" hae="${parseInt(msg.payload.alt || 9999999.0)}" le="9999999.0" ce="9999999.0"/>
197
+ <detail>
198
+ <takv device="${os.hostname()}" os="${os.platform()}" platform="NRedTAK" version="${ver}"/>
199
+ <track course="${msg.payload.bearing || 0}" speed="${parseInt(msg.payload.speed) || 0}"/>
200
+ <contact callsign="${msg.payload.name}"/>
201
+ <remarks source="NRedTAK">${tag}</remarks>
202
+ </detail>
203
+ </event>`
204
+ msg.payload = msg.payload.replace(/>\s+</g, "><");
205
+ node.send(msg);
206
+ }
207
+ // Just has lat, lon (and alt) but no name - assume it's our local position we're updating
208
+ else if (typeof msg.payload === "object" && !msg.payload.hasOwnProperty("name") && msg.payload.hasOwnProperty("lat") && msg.payload.hasOwnProperty("lon")) {
209
+ node.lat = msg.payload.lat;
210
+ node.lon = msg.payload.lon;
211
+ if (msg.payload.hasOwnProperty("alt")) { node.alt = parseInt(msg.payload.alt); }
153
212
  }
154
- else { // Drop anything we don't handle yet.
213
+ // Drop anything we don't handle yet.
214
+ else {
155
215
  node.log("Dropped: "+JSON.stringify(msg.payload));
156
216
  }
157
217
  });
158
218
 
159
- this.on("close", function() {
219
+ node.on("close", function() {
160
220
  // var tim = new Date().toISOString();
161
221
  // var template = `<?xml version="1.0" encoding="utf-8" standalone="yes"?><event version="2.0" uid="${node.uuid}" type="t-x-d-d" how="h-g-i-g-o" time="${tim}" start="${tim}" stale="${tim}"><detail><link uid="${node.uuid}" relation="p-p" type="a-f-G-I-B" /></detail><point le="9999999.0" ce="9999999.0" hae="9999999.0" lon="0" lat="0" /></event>"`;
162
222
  // node.send({payload:template}); // This never happens in time so not useful
@@ -165,5 +225,50 @@ module.exports = function(RED) {
165
225
  });
166
226
  }
167
227
 
168
- RED.nodes.registerType("tak registration",TakRegistrationNode);
169
- };
228
+ var aisToSidc1 = {
229
+ 4: "SFSPXA------",
230
+ 5: "SFSPXM------",
231
+ 6: "SFSPXMP-----",
232
+ 7: "SFSPXMC-----",
233
+ 8: "SFSPXMO-----",
234
+ 9: "SFSPXM------"
235
+ }
236
+
237
+ var aisToSidc2 = {
238
+ 30: "SFSPXF------",
239
+ 31: "SFSPXMTO----",
240
+ 32: "SFSPXMTO--NS",
241
+ 33: "SFSPXFDR----",
242
+ 34: "SFUPND------",
243
+ 35: "SFSP--------",
244
+ 36: "SFSPXR------",
245
+ 37: "SFSPXA------",
246
+ 40: "SFSPXA------", //-
247
+ 50: "SFSPXM------", //-
248
+ 52: "SFSPXMTU----",
249
+ 53: "SFSPNS------",
250
+ 55: "SFSPXL------",
251
+ 58: "SFSPNM------",
252
+ 60: "SFSPXMP-----", //-
253
+ 70: "SFSPXMC-----", //-
254
+ 71: "SFSPXMH-----",
255
+ 72: "SFSPXMH-----",
256
+ 73: "SFSPXMH-----",
257
+ 74: "SFSPXMH-----",
258
+ 80: "SFSPXMO-----", //-
259
+ 90: "SFSPXM------", //-
260
+ }
261
+
262
+ var ais2sidc = function (aisType) {
263
+ //aisType = Number(aisType);
264
+ if (aisType >= 100) { return "GNMPOHTH----"; }
265
+ aisType = aisToSidc2[aisType];
266
+ if (aisType && isNaN(aisType)) { return aisType; }
267
+ aisType = parseInt(aisType / 10);
268
+ aisType = aisToSidc1[aisType];
269
+ if (aisType && isNaN(aisType)) { return aisType; }
270
+ return "SFSPXM------";
271
+ }
272
+
273
+ RED.nodes.registerType("tak registration", TakRegistrationNode);
274
+ };