Send heartbeat package to keep serial alive (#732)

* Send heartbeat package to keep the serial connection alive

* Update meshDevice.ts

---------

Co-authored-by: philon- <philon-@users.noreply.github.com>
This commit is contained in:
Jeremy Gallant
2025-07-24 16:15:27 +02:00
committed by GitHub
parent 5b417a321a
commit 50ca75da0e
4 changed files with 37 additions and 2 deletions

View File

@@ -1,7 +1,6 @@
import { Logger } from "tslog";
import { create, fromBinary, toBinary } from "@bufbuild/protobuf";
import * as Protobuf from "@meshtastic/protobufs";
import { Logger } from "tslog";
import { Constants } from "./constants.ts";
import type { Destination, PacketMetadata, Transport } from "./types.ts";
@@ -40,6 +39,8 @@ export class MeshDevice {
public xModem: Xmodem;
private _heartbeatIntervalId: ReturnType<typeof setInterval> | undefined;
constructor(transport: Transport, configId?: number) {
this.log = new Logger({
name: "iMeshDevice",
@@ -741,6 +742,18 @@ export class MeshDevice {
return this.sendRaw(toBinary(Protobuf.Mesh.ToRadioSchema, toRadio));
}
/**
* Initializes the heartbeat interval, which sends a heartbeat ping every interval milliseconds.
*/
public setHeartbeatInterval(interval: number): void {
if (this._heartbeatIntervalId !== undefined) {
clearInterval(this._heartbeatIntervalId);
}
this._heartbeatIntervalId = setInterval(() => {
this.heartbeat();
}, interval);
}
/**
* Sends a trace route packet to the designated node
*/
@@ -798,6 +811,11 @@ export class MeshDevice {
/** Disconnects from the device **/
public async disconnect(): Promise<void> {
this.log.debug(Emitter[Emitter.Disconnect], "🔌 Disconnecting from device");
if (this._heartbeatIntervalId !== undefined) {
clearInterval(this._heartbeatIntervalId);
}
this.complete();
await this.transport.toDevice.close();
}

View File

@@ -44,6 +44,16 @@ export class Queue {
if (this.queue.findIndex((qi) => qi.id === item.id) !== -1) {
this.remove(item.id);
const decoded = fromBinary(Protobuf.Mesh.ToRadioSchema, item.data);
if (
decoded.payloadVariant.case === "heartbeat" ||
decoded.payloadVariant.case === "wantConfigId"
) {
// heartbeat and wantConfigId packets are not acknowledged by the device, assume success after timeout
resolve(item.id);
return;
}
console.warn(
`Packet ${item.id} of type ${decoded.payloadVariant.case} timed out`,
);

View File

@@ -36,6 +36,10 @@ export const BLE = ({ closeDialog }: TabElementProps) => {
setSelectedDevice(id);
device.addConnection(connection);
subscribeAll(device, connection, messageStore);
const HEARTBEAT_INTERVAL = 5*60*1000;
connection.setHeartbeatInterval(HEARTBEAT_INTERVAL);
closeDialog();
};

View File

@@ -43,6 +43,9 @@ export const Serial = ({ closeDialog }: TabElementProps) => {
device.addConnection(connection);
subscribeAll(device, connection, messageStore);
const HEARTBEAT_INTERVAL = 5*60*1000;
connection.setHeartbeatInterval(HEARTBEAT_INTERVAL);
closeDialog();
};