2026-04-13 21:59:42 -03:00
|
|
|
import { AcInfinityProtocol } from "../src/ble/AcInfinityProtocol";
|
|
|
|
|
|
|
|
|
|
describe("AcInfinityProtocol", () => {
|
|
|
|
|
it("builds get-model-data command with port selector for supported device types", () => {
|
|
|
|
|
const protocol = new AcInfinityProtocol();
|
|
|
|
|
const packet = protocol.buildGetModelData(11, 2);
|
|
|
|
|
|
|
|
|
|
expect(packet[0]).toBe(0xa5);
|
|
|
|
|
expect(packet[9]).toBe(1);
|
|
|
|
|
expect(Array.from(packet.slice(10, 20))).toEqual([
|
|
|
|
|
16, 17, 18, 19, 20, 21, 22, 23, 255, 2
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("builds set-level command with explicit port byte", () => {
|
|
|
|
|
const protocol = new AcInfinityProtocol();
|
|
|
|
|
const packet = protocol.buildSetLevel(11, 2, 5, 3);
|
|
|
|
|
|
|
|
|
|
expect(packet[0]).toBe(0xa5);
|
|
|
|
|
expect(packet[9]).toBe(3);
|
|
|
|
|
expect(Array.from(packet.slice(10, 18))).toEqual([
|
|
|
|
|
16, 1, 2, 18, 1, 5, 255, 3
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("parses telemetry notifications", () => {
|
|
|
|
|
const protocol = new AcInfinityProtocol();
|
|
|
|
|
|
|
|
|
|
const data = Buffer.alloc(20, 0);
|
|
|
|
|
data[0] = 0x1e;
|
|
|
|
|
data[1] = 0xff;
|
|
|
|
|
data[7] = 0x03; // choose_port raw byte
|
|
|
|
|
data[8] = 0x09;
|
|
|
|
|
data[9] = 0x6c; // 24.12C
|
|
|
|
|
data[10] = 0x11;
|
|
|
|
|
data[11] = 0x9e; // 45.10%
|
|
|
|
|
data[12] = 0x00;
|
|
|
|
|
data[13] = 0xb0; // 1.76kPa
|
|
|
|
|
data[17] = 0x62; // fanSpeedGuess=6, workType=2
|
|
|
|
|
|
|
|
|
|
const parsed = protocol.parseTelemetryNotification(data);
|
|
|
|
|
|
|
|
|
|
expect(parsed.temperatureCelsius).toBeCloseTo(24.12, 2);
|
|
|
|
|
expect(parsed.temperatureFahrenheit).toBeCloseTo(75.416, 3);
|
|
|
|
|
expect(parsed.humidityPercent).toBeCloseTo(45.1, 2);
|
|
|
|
|
expect(parsed.vpdKpa).toBeCloseTo(1.76, 2);
|
|
|
|
|
expect(parsed.choosePort).toBe(3);
|
|
|
|
|
expect(parsed.workType).toBe(2);
|
|
|
|
|
expect(parsed.fanSpeedGuess).toBe(6);
|
|
|
|
|
});
|
2026-04-17 06:06:14 -03:00
|
|
|
|
|
|
|
|
it("omits port selector bytes for unsupported device types", () => {
|
|
|
|
|
const protocol = new AcInfinityProtocol();
|
|
|
|
|
const packet = protocol.buildGetModelData(5, 9);
|
|
|
|
|
|
|
|
|
|
expect(packet[0]).toBe(0xa5);
|
|
|
|
|
expect(packet[9]).toBe(1);
|
|
|
|
|
expect(Array.from(packet.slice(10, 18))).toEqual([
|
|
|
|
|
16, 17, 18, 19, 20, 21, 22, 23
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("throws on invalid set-level inputs and malformed telemetry packets", () => {
|
|
|
|
|
const protocol = new AcInfinityProtocol();
|
|
|
|
|
|
|
|
|
|
expect(() => protocol.buildSetLevel(11, 2, 11, 3)).toThrow(
|
|
|
|
|
"level must be an integer between 0 and 10"
|
|
|
|
|
);
|
|
|
|
|
expect(() => protocol.buildSetLevel(11, 1, 4, -1)).toThrow(
|
|
|
|
|
"port must be an integer between 0 and 255"
|
|
|
|
|
);
|
|
|
|
|
expect(() => protocol.parseTelemetryNotification(Buffer.from([0x00, 0x01, 0x02]))).toThrow(
|
|
|
|
|
"unexpected telemetry notification payload"
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("wraps sequence numbers after max uint16", () => {
|
|
|
|
|
const protocol = new AcInfinityProtocol() as unknown as { sequence: number; nextSequence(): number };
|
|
|
|
|
protocol.sequence = 65535;
|
|
|
|
|
|
|
|
|
|
expect(protocol.nextSequence()).toBe(1);
|
|
|
|
|
expect(protocol.nextSequence()).toBe(2);
|
|
|
|
|
});
|
2026-04-13 21:59:42 -03:00
|
|
|
});
|