@meri-imperiumi/signalk-meshtastic 1.1.1 → 1.2.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 CHANGED
@@ -91,6 +91,13 @@ Metrics used:
91
91
 
92
92
  ## Changes
93
93
 
94
+ * 1.2.0 (2025-09-28)
95
+ - Safety for nodes in DB that don't have a "last seen" timestamp
96
+ - Made connection status notifications clearer
97
+ - Attempt at support for Node.js older than 22.x
98
+ * 1.1.2 (2025-09-25)
99
+ - Added support for the new roles from Meshtastic 2.7 (`ROUTER_LATE` and `CLIENT_BASE`)
100
+ - Fixed issue with sending a bell with alerts that have sound enabled
94
101
  * 1.1.1 (2025-09-18)
95
102
  - Fixed empty response text message to digital switching actions
96
103
  - Added support for the proposed Signal K MOB position specification
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meri-imperiumi/signalk-meshtastic",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Signal K plugin for interfacing with the Meshtastic LoRa mesh network",
5
5
  "scripts": {
6
6
  "test": "eslint ."
package/plugin/index.js CHANGED
@@ -5,6 +5,13 @@ const Telemetry = require('./telemetry');
5
5
  const commands = require('./commands/index');
6
6
  const { vesselIcon } = require('./waypoint');
7
7
 
8
+ if (!global.crypto) {
9
+ // Older Node.js versions (like the one bundled in Venus OS
10
+ // don't have crypto module available
11
+ // eslint-disable-next-line global-require
12
+ global.crypto = require('node:crypto');
13
+ }
14
+
8
15
  // The ES modules we'll need to import
9
16
  let MeshDevice;
10
17
  let TransportHTTP;
@@ -146,6 +153,14 @@ function nodeToSignalK(app, node, nodeInfo, settings) {
146
153
  role = 'tak_tracker';
147
154
  break;
148
155
  }
156
+ case 11: {
157
+ role = 'router_late';
158
+ break;
159
+ }
160
+ case 12: {
161
+ role = 'client_base';
162
+ break;
163
+ }
149
164
  default: {
150
165
  break;
151
166
  }
@@ -304,6 +319,10 @@ module.exports = (app) => {
304
319
  // Ignore own node
305
320
  return false;
306
321
  }
322
+ if (!nodes[nodeId].seen) {
323
+ // Somehow never seen
324
+ return false;
325
+ }
307
326
  // Online treshold, should be same as NUM_ONLINE_SECS in Meshtastic fw
308
327
  const onlineSecs = 60 * 60 * 2;
309
328
  if (nodes[nodeId].seen.getTime() > now.getTime() - (onlineSecs * 1000)) {
@@ -454,14 +473,14 @@ module.exports = (app) => {
454
473
  {
455
474
  state: 'warn',
456
475
  lower: 0,
457
- upper: 2,
458
- message: 'Not connected to device',
476
+ upper: 5,
477
+ message: 'Not connected to Meshtastic device',
459
478
  },
460
479
  {
461
480
  state: 'nominal',
462
481
  lower: 7,
463
482
  upper: 8,
464
- message: 'Connected and configured',
483
+ message: 'Meshtastic connected and configured',
465
484
  },
466
485
  ],
467
486
  },
@@ -488,7 +507,9 @@ module.exports = (app) => {
488
507
  Object.keys(nodeDbData)
489
508
  .forEach((nodeNum) => {
490
509
  nodes[nodeNum] = nodeDbData[nodeNum];
491
- nodes[nodeNum].seen = new Date(nodeDbData[nodeNum].seen);
510
+ if (nodeDbData[nodeNum].seen) {
511
+ nodes[nodeNum].seen = new Date(nodeDbData[nodeNum].seen);
512
+ }
492
513
  });
493
514
  app.setPluginStatus(`Connecting to Meshtastic node ${settings.device.address}`);
494
515
  sendMeta();
@@ -823,7 +844,7 @@ module.exports = (app) => {
823
844
  return;
824
845
  }
825
846
  let bell = '';
826
- if (v.value.method && v.value.method.indexOf('sound')) {
847
+ if (v.value.method && v.value.method.indexOf('sound') !== -1) {
827
848
  // Trigger audible bell on receiving Meshtastic devices
828
849
  bell = '\u0007 ';
829
850
  }
@@ -840,30 +861,32 @@ module.exports = (app) => {
840
861
  if (v.path.indexOf('notifications.mob.') === 0) {
841
862
  // This is a notification about a MOB beacon, create waypoint
842
863
  let mobPosition;
843
- let mmsi = 9712234567;
844
864
  let mobVessel = {
845
865
  name: 'MOB beacon',
846
- mmsi,
866
+ mmsi: '9712234567',
847
867
  };
848
- if (v.value.data && v.value.data.position) {
849
- // There is a proposal to include position in the notification
850
- mobPosition = v.value.data.position;
851
- if (v.value.data.mmsi) {
852
- mobVessel.mmsi = mmsi;
853
- }
868
+ if (v.value.data && v.value.data.mmsi) {
869
+ mobVessel.mmsi = v.value.data.mmsi;
870
+ }
871
+ if (v.value.position) {
872
+ // signalk-mob-notifier and freeboard-sk include position in the notification
873
+ mobPosition = v.value.position;
854
874
  } else {
855
875
  // See if the MOB can be found from Signal K tree
856
- mmsi = v.path.split('.').at(-1);
876
+ const mmsi = v.path.split('.').at(-1);
857
877
  mobVessel = app.signalk.root.vessels[`vessels.urn:mrn:imo:mmsi:${mmsi}`];
858
878
  if (mobVessel && mobVessel.navigation.position) {
859
879
  mobPosition = mobVessel.navigation.position;
880
+ if (mobPosition.value) {
881
+ mobPosition = mobPosition.value;
882
+ }
860
883
  }
861
884
  }
862
- if (!mobPosition) {
885
+ if (!mobPosition || !mobPosition.latitude) {
863
886
  return;
864
887
  }
865
888
  const setWaypointMessage = create(Protobuf.Mesh.WaypointSchema, {
866
- id: mmsi,
889
+ id: mobVessel.mmsi,
867
890
  latitudeI: Math.floor(mobPosition.latitude / 1e-7),
868
891
  longitudeI: Math.floor(mobPosition.longitude / 1e-7),
869
892
  expire: Math.floor((new Date().getTime() / 1000) + (1 * 60 * 60)),