UNPKG

@mmote/niimblue-node

Version:

Headless clients for niimbluelib. Command line interface, simple REST server are also included.

137 lines (136 loc) 5.21 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.NiimbotHeadlessBleClient = void 0; const noble_1 = __importDefault(require("@stoprocent/noble")); const niimbluelib_1 = require("@mmote/niimbluelib"); class NiimbotHeadlessBleClient extends niimbluelib_1.NiimbotAbstractClient { constructor() { super(); this.addr = ""; } /** Set device mac address or name for connect */ setAddress(address) { this.addr = address; } static async scan(timeoutMs = 5000) { const items = []; await noble_1.default.waitForPoweredOnAsync(5000); await noble_1.default.startScanningAsync([], false); setTimeout(() => noble_1.default.stopScanningAsync(), timeoutMs ?? 5000); for await (const peripheral of noble_1.default.discoverAsync()) { items.push({ address: peripheral.address, name: peripheral.advertisement.localName || "unknown", }); } return items; } async getDevice(address, timeoutMs = 5000) { await noble_1.default.waitForPoweredOnAsync(5000); return new Promise((resolve, reject) => { let timer; noble_1.default.on("discover", async (peripheral) => { if (peripheral.address === address.toLowerCase() || peripheral.advertisement.localName === address) { clearTimeout(timer); resolve(peripheral); } }); noble_1.default.startScanning([], false, (error) => { if (error) reject(error); }); timer = setTimeout(() => { noble_1.default.stopScanning(); reject(new Error("Device not found")); }, timeoutMs ?? 5000); }); } async connectToDevice(address, timeoutMs = 5000) { const periph = await this.getDevice(address, timeoutMs); await periph.connectAsync(); const services = await periph.discoverServicesAsync(); let channelCharacteristic; for (const service of services) { if (service.uuid.length < 5) { continue; } const characteristics = await service.discoverCharacteristicsAsync(); const suitableCharacteristic = characteristics.find((ch) => ch.properties.includes("notify") && ch.properties.includes("writeWithoutResponse")); if (suitableCharacteristic) { channelCharacteristic = suitableCharacteristic; break; } } if (channelCharacteristic === undefined) { await periph.disconnectAsync(); throw new Error("Unable to find suitable channel characteristic"); } periph.on("disconnect", () => { this.stopHeartbeat(); this.emit("disconnect", new niimbluelib_1.DisconnectEvent()); this.device = undefined; this.channel = undefined; }); channelCharacteristic.on("data", (data, isNotification) => { if (isNotification) this.processRawPacket(new Uint8Array(data)); }); await channelCharacteristic.subscribeAsync(); this.channel = channelCharacteristic; this.device = periph; } async connect() { await this.disconnect(); if (!this.addr) { throw new Error("Device address or name not set"); } await this.connectToDevice(this.addr); try { await this.initialNegotiate(); await this.fetchPrinterInfo(); } catch (e) { console.error("Unable to fetch printer info."); console.error(e); } const result = { deviceName: this.device.advertisement.localName ?? this.addr, result: this.info.connectResult ?? niimbluelib_1.ConnectResult.FirmwareErrors, }; this.emit("connect", new niimbluelib_1.ConnectEvent(result)); return result; } isConnected() { return this.device !== undefined && this.channel !== undefined; } async disconnect() { this.stopHeartbeat(); if (this.device !== undefined) { await this.device.disconnectAsync(); } this.device = undefined; this.channel = undefined; } async sendRaw(data, force) { const send = async () => { if (!this.isConnected()) { this.disconnect(); throw new Error("Not connected"); } await niimbluelib_1.Utils.sleep(this.packetIntervalMs); await this.channel.writeAsync(Buffer.from(data), true); this.emit("rawpacketsent", new niimbluelib_1.RawPacketSentEvent(data)); }; if (force) { await send(); } else { await this.mutex.runExclusive(send); } } } exports.NiimbotHeadlessBleClient = NiimbotHeadlessBleClient;