feat: Switch to noble fork

This commit is contained in:
2026-02-04 15:27:27 +07:00
parent 1dce024b1a
commit 12a20f6213
5 changed files with 621 additions and 988 deletions
+33 -3
View File
@@ -1,8 +1,8 @@
import { EventEmitter } from "node:events";
EventEmitter.defaultMaxListeners = 20;
import noble from "@abandonware/noble";
import type { Peripheral, Characteristic } from "@abandonware/noble";
import noble from "@stoprocent/noble";
import type { Peripheral, Characteristic } from "@stoprocent/noble";
import type { BLEConfig, ProtocolConfig } from "../protocol/index.ts";
import { PacketType } from "../protocol/index.ts";
import { DeviceNotFoundError, ConnectionError } from "../utils/errors.ts";
@@ -297,6 +297,12 @@ export class BleUploader {
return match[1]; // Return short UUID part
}
// For short UUIDs (3-4 hex chars), pad with zeros to 4 chars for consistent comparison
// This handles cases like "1f1" vs "01f1"
if (cleaned.length <= 4) {
return cleaned.padStart(4, "0");
}
return cleaned;
}
@@ -425,10 +431,34 @@ export class BleUploader {
// Stop scanning before connecting
await noble.stopScanningAsync().catch(() => {});
// Check peripheral state before connecting
logger.debug(
`Peripheral state before connect: ${this.peripheral!.state}`,
);
// If already connected, disconnect first to ensure clean state
if (
this.peripheral!.state === "connected" ||
this.peripheral!.state === "connecting"
) {
logger.debug(
"Device already connected/connecting, disconnecting first...",
);
await this.peripheral!.disconnectAsync().catch(() => {});
await this.sleep(500); // Brief delay after disconnect
}
// Connect to device
logger.info("Connecting to device...", LogEventType.CONNECT_START);
const connectStartTime = Date.now();
await this.peripheral!.connectAsync();
logger.info("Connected to device", LogEventType.CONNECTED);
const connectDuration = Date.now() - connectStartTime;
logger.info(
`Connected to device (took ${connectDuration}ms)`,
LogEventType.CONNECTED,
);
// Handle disconnect events
this.peripheral!.once("disconnect", () => {
+28
View File
@@ -32,6 +32,7 @@ export class BeamBoxUploader {
private imageProcessor: ImageProcessor;
private payloadBuilder: PayloadBuilder;
private imageConfig: ImageConfig;
private verbose: boolean = false;
constructor(
deviceAddress?: string,
@@ -41,6 +42,7 @@ export class BeamBoxUploader {
imageConfig?: ImageConfig,
verbose: boolean = false,
) {
this.verbose = verbose;
this.imageConfig = imageConfig ?? DEFAULT_IMAGE_CONFIG;
this.ble = new BleUploader(
deviceAddress ?? null,
@@ -315,20 +317,46 @@ export class BeamBoxUploader {
// Wait for at least one status notification (PacketType.DEVICE_STATUS)
const startTime = Date.now();
const checkInterval = 100;
let statusReceived = false;
let lastNotificationCount = 0;
while (Date.now() - startTime < timeoutMs) {
const deviceStatus = this.ble.getDeviceStatus();
const notifications = this.ble.getNotifications();
// Log progress if we got new notifications
if (notifications.length > lastNotificationCount) {
logger.debug(`Received ${notifications.length} total notifications so far...`);
lastNotificationCount = notifications.length;
}
if (deviceStatus && deviceStatus.type === 13) {
logger.info(
`Device status received: ${JSON.stringify(deviceStatus)}`,
);
logger.info("Device is ready for upload");
statusReceived = true;
break;
}
await this.sleep(checkInterval);
}
if (!statusReceived) {
const notifications = this.ble.getNotifications();
logger.warning(
`Device status (type 13) not received within ${timeoutMs}ms timeout. Got ${notifications.length} notifications. Proceeding with available data.`,
);
// Log what we did receive if in verbose mode
if (notifications.length > 0 && this.verbose) {
logger.debug("Received notification types:");
notifications.forEach((n, i) => {
logger.debug(` [${i}] type: ${n.parsed?.jsonData?.type || 'unknown'}, data: ${JSON.stringify(n.parsed?.jsonData || {})}`);
});
}
}
const notifications = this.ble.getNotifications();
logger.info(`Received ${notifications.length} notifications from device`);