import { BleControllerClient, BleTelemetryReading } from "../src/ble/BleControllerClient"; import { Logger } from "../src/observability/Logger"; import { BleControlBackend } from "../src/services/BleControlBackend"; class FakeBleClient implements BleControllerClient { public lastSet: { mac: string; portByte: number; speedLevel: number } | null = null; public telemetry: BleTelemetryReading = { temperatureCelsius: 24.06, temperatureFahrenheit: 75.31, humidityPercent: 41.06, vpdKpa: 1.76, choosePort: 3, workType: 2, fanSpeedGuess: 7, receivedAtEpochSeconds: 1_700_000_123 }; public async verifyConnection(): Promise { return; } public async readTelemetry(): Promise { return this.telemetry; } public async setPortSpeed(macAddress: string, portByte: number, speedLevel: number): Promise { this.lastSet = { mac: macAddress, portByte, speedLevel }; } } describe("BleControlBackend", () => { it("pairs and enforces allowed MAC list", async () => { const client = new FakeBleClient(); const backend = new BleControlBackend({ defaultMac: null, allowedMacs: ["58:8C:81:C6:FC:F6"], requestTimeoutMs: 10000, scanTimeoutMs: 10000, deviceType: 11, portBase: 1, logger: new Logger("error", "test"), client }); await expect(backend.pair("11:22:33:44:55:66")).rejects.toThrow("mac address is not in TY_BLE_ALLOWED_MACS"); const status = await backend.pair("58:8c:81:c6:fc:f6"); expect(status.controllerMac).toBe("58:8C:81:C6:FC:F6"); expect(status.connected).toBe(true); }); it("maps port numbers to device bytes and updates speed cache", async () => { const client = new FakeBleClient(); const backend = new BleControlBackend({ defaultMac: "58:8C:81:C6:FC:F6", allowedMacs: [], requestTimeoutMs: 10000, scanTimeoutMs: 10000, deviceType: 11, portBase: 1, logger: new Logger("error", "test"), client }); await backend.setPortSpeed(4, 9); expect(client.lastSet).toEqual({ mac: "58:8C:81:C6:FC:F6", portByte: 3, speedLevel: 9 }); const ports = await backend.getPorts(); expect(ports.find((p) => p.port === 4)?.currentSpeedLevel).toBe(9); }); it("builds a climate snapshot from BLE telemetry", async () => { const client = new FakeBleClient(); const backend = new BleControlBackend({ defaultMac: "58:8C:81:C6:FC:F6", allowedMacs: [], requestTimeoutMs: 10000, scanTimeoutMs: 10000, deviceType: 11, portBase: 1, logger: new Logger("error", "test"), client }); const snapshot = await backend.refreshTelemetry(); const controller = snapshot.controllers[0]; expect(controller?.temperatureCelsius).toBeCloseTo(24.06, 2); expect(controller?.relativeHumidityRatio).toBeCloseTo(0.4106, 4); expect(controller?.vpdKpa).toBeCloseTo(1.76, 2); expect(controller?.ports.find((p) => p.port === 4)?.currentSpeedLevel).toBe(7); }); });