From 91f7de36870ed7b0f00cc544aeabd283cd971d5d Mon Sep 17 00:00:00 2001 From: MultiMote <contact@mmote.ru> Date: Thu, 10 Oct 2024 21:58:24 +0300 Subject: [PATCH] Improve heartbeat functionality, autostart heartbeat --- src/client/bluetooth_impl.ts | 1 - src/client/events.ts | 9 +++++++++ src/client/index.ts | 34 +++++++++++++++++++++++++++++----- src/client/serial_impl.ts | 1 - src/packets/abstraction.ts | 15 ++++++++++++--- 5 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/client/bluetooth_impl.ts b/src/client/bluetooth_impl.ts index fbb85a8..bb1f32b 100644 --- a/src/client/bluetooth_impl.ts +++ b/src/client/bluetooth_impl.ts @@ -43,7 +43,6 @@ export class NiimbotBluetoothClient extends NiimbotAbstractClient { this.gattServer = undefined; this.channel = undefined; this.info = {}; - this.stopHeartbeat(); this.dispatchTypedEvent("disconnect", new DisconnectEvent()); device.removeEventListener("gattserverdisconnected", disconnectListener); }; diff --git a/src/client/events.ts b/src/client/events.ts index b3d8230..42316aa 100644 --- a/src/client/events.ts +++ b/src/client/events.ts @@ -57,6 +57,14 @@ export class HeartbeatEvent extends Event { } } +export class HeartbeatFailedEvent extends Event { + failedAttempts: number; + constructor(failedAttempts: number) { + super("heartbeatfailed"); + this.failedAttempts = failedAttempts; + } +} + export class PrinterInfoFetchedEvent extends Event { info: PrinterInfo; constructor(info: PrinterInfo) { @@ -92,6 +100,7 @@ export interface ClientEventMap { packetreceived: PacketReceivedEvent; packetsent: PacketSentEvent; heartbeat: HeartbeatEvent; + heartbeatfailed: HeartbeatFailedEvent; printerinfofetched: PrinterInfoFetchedEvent; printprogress: PrintProgressEvent; } diff --git a/src/client/index.ts b/src/client/index.ts index fb571cf..e0ea156 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -8,7 +8,7 @@ import { NiimbotPacket, } from "../packets"; import { PrinterModelMeta, getPrinterMetaById } from "../printer_models"; -import { ClientEventMap, PacketSentEvent, PrinterInfoFetchedEvent, HeartbeatEvent } from "./events"; +import { ClientEventMap, PacketSentEvent, PrinterInfoFetchedEvent, HeartbeatEvent, HeartbeatFailedEvent } from "./events"; import { getPrintTaskVersion, PrintTaskVersion } from "../print_task_versions"; export type ConnectionInfo = { @@ -33,12 +33,17 @@ export abstract class NiimbotAbstractClient extends TypedEventTarget<ClientEvent public readonly abstraction: Abstraction; protected info: PrinterInfo = {}; private heartbeatTimer?: NodeJS.Timeout; + private heartbeatFails: number = 0; + private heartbeatIntervalMs: number = 2_000; + /** https://github.com/MultiMote/niimblue/issues/5 */ protected packetIntervalMs: number = 10; constructor() { super(); this.abstraction = new Abstraction(this); + this.addEventListener("connect", () => this.startHeartbeat()) + this.addEventListener("disconnect", () => this.stopHeartbeat()) } /** Connect to printer port */ @@ -102,19 +107,38 @@ export abstract class NiimbotAbstractClient extends TypedEventTarget<ClientEvent } /** - * Starts the heartbeat timer, "heartbeat" is emitted after packet received. + * Set interval for {@link startHeartbeat}. * * @param interval Heartbeat interval, default is 1000ms */ - public startHeartbeat(intervalMs: number = 1000): void { + public setHeartbeatInterval(intervalMs: number): void { + this.heartbeatIntervalMs = intervalMs; + } + + + /** + * Starts the heartbeat timer, "heartbeat" is emitted after packet received. + * + * If you need to change interval, call {@link setHeartbeatInterval} before. + */ + public startHeartbeat(): void { + this.heartbeatFails = 0; + + this.stopHeartbeat(); + this.heartbeatTimer = setInterval(() => { this.abstraction .heartbeat() .then((data) => { + this.heartbeatFails = 0; this.dispatchTypedEvent("heartbeat", new HeartbeatEvent(data)); }) - .catch(console.error); - }, intervalMs); + .catch((e) => { + console.error(e); + this.heartbeatFails++; + this.dispatchTypedEvent("heartbeatfailed", new HeartbeatFailedEvent(this.heartbeatFails)); + }); + }, this.heartbeatIntervalMs); } public stopHeartbeat(): void { diff --git a/src/client/serial_impl.ts b/src/client/serial_impl.ts index bb87809..6beaed7 100644 --- a/src/client/serial_impl.ts +++ b/src/client/serial_impl.ts @@ -25,7 +25,6 @@ export class NiimbotSerialClient extends NiimbotAbstractClient { _port.addEventListener("disconnect", () => { this.port = undefined; - console.log("serial disconnect event"); this.dispatchTypedEvent("disconnect", new DisconnectEvent()); }); diff --git a/src/packets/abstraction.ts b/src/packets/abstraction.ts index b02d293..ae48c01 100644 --- a/src/packets/abstraction.ts +++ b/src/packets/abstraction.ts @@ -92,8 +92,8 @@ export class Abstraction { } /** Send packet and wait for response */ - private async send(packet: NiimbotPacket): Promise<NiimbotPacket> { - return this.client.sendPacketWaitResponse(packet, this.timeout); + private async send(packet: NiimbotPacket, forceTimeout?: number): Promise<NiimbotPacket> { + return this.client.sendPacketWaitResponse(packet, forceTimeout ?? this.timeout); } public async getPrintStatus(): Promise<PrintStatus> { @@ -200,7 +200,7 @@ export class Abstraction { } public async heartbeat(): Promise<HeartbeatData> { - const packet = await this.send(PacketGenerator.heartbeat(HeartbeatType.Advanced1)); + const packet = await this.send(PacketGenerator.heartbeat(HeartbeatType.Advanced1), 500); const info: HeartbeatData = { paperState: -1, @@ -342,6 +342,15 @@ export class Abstraction { await this.send(PacketGenerator.printerReset()); } + /** + * + * Call client.stopHeartbeat before print is started! + * + * @param taskVersion + * @param image + * @param options + * @param timeout + */ public async print( taskVersion: PrintTaskVersion, image: EncodedImage,