Skip to content

Commit

Permalink
Merge pull request #115 from benbrown/fix-serial-heartbeat
Browse files Browse the repository at this point in the history
Add serial heartbeat to keep alive
  • Loading branch information
thebentern authored Nov 22, 2024
2 parents c6c26f1 + 70c301a commit 715e35d
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/adapters/serialConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ export class SerialConnection extends MeshDevice {
* through a transform stream (https://stackoverflow.com/questions/71262432) */
private pipePromise?: Promise<void>;

/* Reference for the heartbeat ping interval so it can be canceled on disconnect. */
private heartbeatInterval?: ReturnType<typeof setInterval> | undefined;

/**
* Fires when `disconnect()` is called, used to instruct serial port and
* readers to release there locks
Expand All @@ -44,6 +47,7 @@ export class SerialConnection extends MeshDevice {
this.transformer = undefined;
this.onReleaseEvent = new SimpleEventDispatcher<boolean>();
this.preventLock = false;
this.heartbeatInterval = undefined;

this.log.debug(
Types.Emitter[Types.Emitter.Constructor],
Expand Down Expand Up @@ -125,6 +129,7 @@ export class SerialConnection extends MeshDevice {
});

this.preventLock = false;

/** Connect to device */
await this.port
.open({
Expand All @@ -151,6 +156,14 @@ export class SerialConnection extends MeshDevice {
this.configure().catch(() => {
// TODO: FIX, workaround for `wantConfigId` not getting acks.
});

// Set up an interval to send a heartbeat ping once every minute.
// The firmware requires at least one ping per 15 minutes, so this should be more than enough.
this.heartbeatInterval = setInterval(() => {
this.heartbeat().catch((err) => {
console.error('Heartbeat error', err);
});
}, 60*1000);
} else {
console.log("not readable or writable");
}
Expand Down Expand Up @@ -180,6 +193,12 @@ export class SerialConnection extends MeshDevice {
if (this.port?.readable) {
await this.port?.close();
}

// stop the interval when disconnecting.
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval);
this.heartbeatInterval = undefined;
}
// -------
this.updateDeviceStatus(Types.DeviceStatusEnum.DeviceDisconnected);
this.complete();
Expand Down
17 changes: 17 additions & 0 deletions src/meshDevice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,23 @@ export abstract class MeshDevice {
return this.sendRaw(toBinary(Protobuf.Mesh.ToRadioSchema, toRadio));
}

/** Serial connection requires a heartbeat ping to stay connected, otherwise times out after 15 minutes */
public heartbeat(): Promise<number> {
this.log.debug(
Types.Emitter[Types.Emitter.Ping],
"❤️ Send heartbeat ping to radio",
);

const toRadio = create(Protobuf.Mesh.ToRadioSchema, {
payloadVariant: {
case: "heartbeat",
value: {},
},
});

return this.sendRaw(toBinary(Protobuf.Mesh.ToRadioSchema, toRadio));
}

/** Sends a trace route packet to the designated node */
public async traceRoute(destination: number): Promise<number> {
const routeDiscovery = create(Protobuf.Mesh.RouteDiscoverySchema, {
Expand Down

0 comments on commit 715e35d

Please sign in to comment.