1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import type { TimeSyncSummary } from "../src/inspection.js";
import { compareDeviceClock } from "../src/sync.js";
import { capabilitiesFromTimeSync, planTimeSync } from "../src/timesync.js";
/**
* Tests driven by the captured `inspect --json` output of the real device
* (IKEA ALPSTUGA air quality monitor, firmware 1.0.26), per the plan: the
* sync behavior is derived from inspected capabilities, not assumptions.
*/
const fixture = JSON.parse(readFileSync(join(__dirname, "fixtures", "alpstuga-inspect.json"), "utf8")) as {
basicInformation: { vendorName: string; productName: string };
timeSynchronization: TimeSyncSummary;
};
describe("alpstuga fixture", () => {
it("is the expected device", () => {
expect(fixture.basicInformation.vendorName).toBe("IKEA of Sweden");
expect(fixture.timeSynchronization).not.toBeNull();
});
it("derives capabilities from the inspection", () => {
const capabilities = capabilitiesFromTimeSync(fixture.timeSynchronization);
expect(capabilities).toEqual({
timeZoneFeature: true,
supportsSetUtcTime: true,
supportsSetTimeZone: true,
supportsSetDstOffset: true,
timeZoneListMaxSize: 2,
dstOffsetListMaxSize: 2,
});
});
it("plans UTC + time zone + a 2-entry DST list for this device", () => {
const capabilities = capabilitiesFromTimeSync(fixture.timeSynchronization);
const plan = planTimeSync(capabilities, "America/Chicago", new Date("2026-07-26T00:00:00Z"));
expect(plan.setUtcTime).toBe(true);
expect(plan.timeZone).toEqual([
{ offset: -21600, validAt: 946_684_800_000_000n, name: "America/Chicago" },
]);
expect(plan.dstOffsets).toHaveLength(2);
expect(plan.dstOffsets![0]!.offset).toBe(3600);
expect(plan.dstOffsets![1]!.offset).toBe(0);
});
it("reads the fixture's utcTime as healthy Unix-epoch microseconds", () => {
// matter.js's TlvEpochUs decodes wire values to Unix-epoch microseconds,
// so the fixture's utcTime (read at commissioning, 2026-07-27T00:18:15Z
// wall clock) compares cleanly against that instant with no epoch shift.
const attribute = fixture.timeSynchronization.attributes.find(a => a.name === "utcTime");
const deviceMicros = BigInt(attribute!.value as string);
const captureInstant = BigInt(Date.parse("2026-07-27T00:18:20Z")) * 1_000n;
const comparison = compareDeviceClock(deviceMicros, captureInstant);
expect(comparison.epochShifted).toBe(false);
expect(comparison.deviceTime).toBe("2026-07-27T00:18:15.000Z");
const effective = comparison.effectiveDeltaMicroseconds!;
const magnitude = effective < 0n ? -effective : effective;
expect(magnitude < 60n * 1_000_000n).toBe(true);
});
it("degrades to UTC-only when the TimeZone feature is absent", () => {
const utcOnly: TimeSyncSummary = {
...fixture.timeSynchronization,
supportedFeatures: { ...fixture.timeSynchronization.supportedFeatures, timeZone: false },
supportedCommands: {
...fixture.timeSynchronization.supportedCommands,
setTimeZone: false,
setDstOffset: false,
},
};
const plan = planTimeSync(capabilitiesFromTimeSync(utcOnly), "America/Chicago");
expect(plan.setUtcTime).toBe(true);
expect(plan.timeZone).toBeNull();
expect(plan.dstOffsets).toBeNull();
});
});
|