@meri-imperiumi/signalk-meshtastic 1.2.2 → 1.2.4

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,11 @@ Metrics used:
91
91
 
92
92
  ## Changes
93
93
 
94
+ * 1.2.4 (2026-02-15)
95
+ - Corrupted Node DB file should no longer crash the plugin
96
+ * 1.2.3 (2025-10-15)
97
+ - Nodes that haven't been seen in last two days are no longer registered to Signal K data structure
98
+ - Added safeties for various non-numeric telemetry and coordinate values
94
99
  * 1.2.2 (2025-10-01)
95
100
  - Set "last seen" timestamp of nodes based on packet payloads, not the time they're received
96
101
  - Send timestamp with telemetry
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meri-imperiumi/signalk-meshtastic",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "Signal K plugin for interfacing with the Meshtastic LoRa mesh network",
5
5
  "scripts": {
6
6
  "test": "eslint ."
@@ -47,7 +47,7 @@ module.exports = {
47
47
  latitudeI: Math.floor(waypointVessel.navigation.position.value.latitude / 1e-7),
48
48
  longitudeI: Math.floor(waypointVessel.navigation.position.value.longitude / 1e-7),
49
49
  expire: Math.floor((new Date().getTime() / 1000) + (length * 60 * 60)),
50
- name: waypointVessel.name,
50
+ name: waypointVessel.name || waypointVessel.mmsi,
51
51
  description: `AIS vessel ${waypointVessel.mmsi}`,
52
52
  icon: vesselIcon(waypointVessel),
53
53
  });
package/plugin/index.js CHANGED
@@ -101,7 +101,7 @@ function nodeToSignalK(app, node, nodeInfo, settings) {
101
101
  },
102
102
  ];
103
103
 
104
- if (nodeInfo.position) {
104
+ if (nodeInfo.position && Number.isFinite(nodeInfo.position.latitudeI)) {
105
105
  values.push({
106
106
  path: 'navigation.position',
107
107
  value: {
@@ -511,7 +511,13 @@ module.exports = (app) => {
511
511
  readFile(nodeDbFile, 'utf-8')
512
512
  .catch(() => '{}')
513
513
  .then((nodeDb) => {
514
- const nodeDbData = JSON.parse(nodeDb);
514
+ let nodeDbData;
515
+ try {
516
+ nodeDbData = JSON.parse(nodeDb);
517
+ } catch (e) {
518
+ app.debug('Error reading Node DB file', e);
519
+ nodeDbData = {};
520
+ }
515
521
  Object.keys(nodeDbData)
516
522
  .forEach((nodeNum) => {
517
523
  nodes[nodeNum] = nodeDbData[nodeNum];
@@ -561,10 +567,13 @@ module.exports = (app) => {
561
567
  nodes[nodeInfo.num].publicKey = Buffer.from(nodeInfo.user.publicKey).toString('base64');
562
568
  }
563
569
  nodes[nodeInfo.num].seen = new Date(nodeInfo.lastHeard * 1000);
564
- const ctx = nodeToSignalK(app, nodes[nodeInfo.num], nodeInfo, settings);
565
- if (ctx && ctx.indexOf('vessels.urn:mrn:imo:mmsi:') === 0) {
566
- // We have an MMSI match, store it
567
- nodes[nodeInfo.num].mmsi = ctx.split(':').at(-1);
570
+ if (nodes[nodeInfo.num].seen > Date.now() - (1000 * 60 * 60 * 24 * 2)) {
571
+ // Node seen less than a two days ago, register with SK
572
+ const ctx = nodeToSignalK(app, nodes[nodeInfo.num], nodeInfo, settings);
573
+ if (ctx && ctx.indexOf('vessels.urn:mrn:imo:mmsi:') === 0) {
574
+ // We have an MMSI match, store it
575
+ nodes[nodeInfo.num].mmsi = ctx.split(':').at(-1);
576
+ }
568
577
  }
569
578
  setConnectionStatus();
570
579
  writeNodeDb();
@@ -754,7 +763,7 @@ module.exports = (app) => {
754
763
  },
755
764
  {
756
765
  path: 'navigation.gnss.antennaAltitude',
757
- value: position.data.altitude,
766
+ value: position.data.altitude || 0,
758
767
  },
759
768
  ];
760
769
  app.handleMessage('signalk-meshtastic', {
@@ -847,7 +856,8 @@ module.exports = (app) => {
847
856
  // Not connected to Meshtastic yet
848
857
  return;
849
858
  }
850
- if (v.value.latitude === null) {
859
+ if (!Number.isFinite(v.value.latitude)
860
+ || !Number.isFinite(v.value.longitude)) {
851
861
  // No position
852
862
  return;
853
863
  }
@@ -911,7 +921,7 @@ module.exports = (app) => {
911
921
  }
912
922
  }
913
923
  }
914
- if (!mobPosition || !mobPosition.latitude) {
924
+ if (!mobPosition || !Number.isFinite(mobPosition.latitude)) {
915
925
  return;
916
926
  }
917
927
  const setWaypointMessage = create(Protobuf.Mesh.WaypointSchema, {
@@ -14,16 +14,16 @@ class Telemetry {
14
14
 
15
15
  toMeshtastic() {
16
16
  const values = {};
17
- if (this.data['environment.outside.temperature']) {
17
+ if (Number.isFinite(this.data['environment.outside.temperature'])) {
18
18
  values.temperature = this.data['environment.outside.temperature'] - 273.15;
19
19
  }
20
- if (this.data['environment.outside.relativeHumidity']) {
20
+ if (Number.isFinite(this.data['environment.outside.relativeHumidity'])) {
21
21
  values.relativeHumidity = this.data['environment.outside.relativeHumidity'] * 100;
22
22
  }
23
- if (this.data['environment.outside.pressure']) {
23
+ if (Number.isFinite(this.data['environment.outside.pressure'])) {
24
24
  values.barometricPressure = this.data['environment.outside.pressure'] / 100;
25
25
  }
26
- if (this.data['environment.wind.directionTrue']) {
26
+ if (Number.isFinite(this.data['environment.wind.directionTrue'])) {
27
27
  values.windDirection = Math.floor(this.data['environment.wind.directionTrue'] * (180 / Math.PI));
28
28
  }
29
29
  if (this.data['environment.wind.speedOverGround'] && this.data['environment.wind.speedOverGround'].length) {
@@ -38,16 +38,16 @@ class Telemetry {
38
38
  // Clear wind history
39
39
  this.data['environment.wind.speedOverGround'] = [];
40
40
  }
41
- if (this.data['electrical.batteries.house.voltage']) {
41
+ if (Number.isFinite(this.data['electrical.batteries.house.voltage'])) {
42
42
  values.voltage = this.data['electrical.batteries.house.voltage'];
43
43
  }
44
- if (this.data['electrical.batteries.house.current']) {
44
+ if (Number.isFinite(this.data['electrical.batteries.house.current'])) {
45
45
  values.current = this.data['electrical.batteries.house.current'] * 1000;
46
46
  }
47
- if (this.data['navigation.anchor.distanceFromBow']) {
47
+ if (Number.isFinite(this.data['navigation.anchor.distanceFromBow'])) {
48
48
  // Using distance is a bit silly here as the unit is mm, but what can we do
49
49
  values.distance = this.data['navigation.anchor.distanceFromBow'] * 1000;
50
- } else if (this.data['environment.depth.belowSurface']) {
50
+ } else if (Number.isFinite(this.data['environment.depth.belowSurface'])) {
51
51
  // If not anchored, report depth as distance. Still mm.
52
52
  values.distance = this.data['environment.depth.belowSurface'] * 1000;
53
53
  }
@@ -55,6 +55,9 @@ class Telemetry {
55
55
  }
56
56
 
57
57
  updateWindSpeed(windSpeed) {
58
+ if (!Number.isFinite(windSpeed)) {
59
+ return;
60
+ }
58
61
  if (!this.data['environment.wind.speedOverGround']) {
59
62
  this.data['environment.wind.speedOverGround'] = [];
60
63
  }