typhon/tests/BleControlBackend.test.ts

165 lines
4.9 KiB
TypeScript
Raw Permalink Normal View History

import {
BleControllerClient,
BleFeatureNotSupportedError,
BleTelemetryReading,
BleWifiNetworkCredentials
} 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 lastWifiRecovery: { mac: string; credentials: BleWifiNetworkCredentials } | null = null;
public wifiRecoveryMode: "ok" | "unsupported" = "ok";
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<void> {
return;
}
public async readTelemetry(): Promise<BleTelemetryReading> {
return this.telemetry;
}
public async setPortSpeed(macAddress: string, portByte: number, speedLevel: number): Promise<void> {
this.lastSet = { mac: macAddress, portByte, speedLevel };
}
public async recoverWifi(macAddress: string, credentials: BleWifiNetworkCredentials): Promise<void> {
if (this.wifiRecoveryMode === "unsupported") {
throw new BleFeatureNotSupportedError("wifi recovery unsupported");
}
this.lastWifiRecovery = { mac: macAddress, credentials };
}
}
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);
});
it("sends wifi recovery credentials through BLE client", 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 result = await backend.recoverWifi({
ssid: "atlas-net",
password: "supersecret",
hidden: true
});
expect(result.queued).toBe(true);
expect(client.lastWifiRecovery).toEqual({
mac: "58:8C:81:C6:FC:F6",
credentials: {
ssid: "atlas-net",
password: "supersecret",
hidden: true
}
});
});
it("returns 501 when wifi recovery is unsupported by BLE client", async () => {
const client = new FakeBleClient();
client.wifiRecoveryMode = "unsupported";
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 expect(
backend.recoverWifi({
ssid: "atlas-net",
password: "supersecret",
hidden: false
})
).rejects.toThrow("wifi recovery over BLE is not implemented by this client yet");
});
});