@camstack/addon-provider-velux 0.2.154 → 0.2.155
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/addon.js +465 -189
- package/dist/addon.mjs +465 -189
- package/package.json +2 -2
package/dist/addon.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { connect } from "node:tls";
|
|
3
3
|
import { setImmediate as setImmediate$1 } from "timers/promises";
|
|
4
|
-
import { connect as connect$1 } from "node:net";
|
|
5
4
|
//#region \0rolldown/runtime.js
|
|
6
5
|
var __create = Object.create;
|
|
7
6
|
var __defProp = Object.defineProperty;
|
|
@@ -35,7 +34,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
35
34
|
}) : target, mod));
|
|
36
35
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
37
36
|
//#endregion
|
|
38
|
-
//#region ../types/dist/event-category-
|
|
37
|
+
//#region ../types/dist/event-category-BmPm98n0.mjs
|
|
39
38
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
40
39
|
EventCategory["SystemBoot"] = "system.boot";
|
|
41
40
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -519,6 +518,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
519
518
|
EventCategory["RunningStarted"] = "running.started";
|
|
520
519
|
/** Mirrors `runningStateCapability.events.onFinished`. */
|
|
521
520
|
EventCategory["RunningFinished"] = "running.finished";
|
|
521
|
+
/** Mirrors `deviceRunsCapability.events.onRunOpened` - a durable run record opened. */
|
|
522
|
+
EventCategory["DeviceRunOpened"] = "device-run.opened";
|
|
523
|
+
/** Mirrors `deviceRunsCapability.events.onRunClosed` - a durable run record closed. */
|
|
524
|
+
EventCategory["DeviceRunClosed"] = "device-run.closed";
|
|
522
525
|
/**
|
|
523
526
|
* Cap event fired by every device that registers the `event-emitter`
|
|
524
527
|
* capability. Mirrors `eventEmitterCapability.events.onEvent`. Carries
|
|
@@ -5867,7 +5870,7 @@ var ZodIssueCode = {
|
|
|
5867
5870
|
var ZodFirstPartyTypeKind;
|
|
5868
5871
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5869
5872
|
//#endregion
|
|
5870
|
-
//#region ../types/dist/sleep-
|
|
5873
|
+
//#region ../types/dist/sleep-BKzhQTSm.mjs
|
|
5871
5874
|
/**
|
|
5872
5875
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5873
5876
|
* window to float samples (D455).
|
|
@@ -9380,6 +9383,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9380
9383
|
"device-ops",
|
|
9381
9384
|
"device-provider",
|
|
9382
9385
|
"device-removal-hook",
|
|
9386
|
+
"device-runs",
|
|
9383
9387
|
"device-state",
|
|
9384
9388
|
"device-status",
|
|
9385
9389
|
"dishwasher",
|
|
@@ -11324,7 +11328,7 @@ object({
|
|
|
11324
11328
|
params: record(string(), union([string(), number()])).optional()
|
|
11325
11329
|
});
|
|
11326
11330
|
//#endregion
|
|
11327
|
-
//#region ../types/dist/composition-
|
|
11331
|
+
//#region ../types/dist/composition-BiKWlUCc.mjs
|
|
11328
11332
|
/**
|
|
11329
11333
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11330
11334
|
*
|
|
@@ -12257,7 +12261,15 @@ var HelperSpecSchema = discriminatedUnion("kind", [
|
|
|
12257
12261
|
thresholdWatts: number().positive(),
|
|
12258
12262
|
startDwellMs: number().int().nonnegative(),
|
|
12259
12263
|
stopDwellMs: number().int().nonnegative(),
|
|
12260
|
-
member: HelperMemberSchema
|
|
12264
|
+
member: HelperMemberSchema,
|
|
12265
|
+
/**
|
|
12266
|
+
* The plug that powers the appliance (`switch.on`). Optional: when set, the
|
|
12267
|
+
* composition carries a `power-source` feature, so the hub can cut and restore
|
|
12268
|
+
* that plug (power-source link of a NEW-target composition).
|
|
12269
|
+
*/
|
|
12270
|
+
powerSwitch: HelperMemberSchema.optional(),
|
|
12271
|
+
/** How long a forced restart keeps the plug off; the cap's default when unset. */
|
|
12272
|
+
offSeconds: number().optional()
|
|
12261
12273
|
}),
|
|
12262
12274
|
object({
|
|
12263
12275
|
kind: literal("statistic"),
|
|
@@ -13655,7 +13667,13 @@ var MigrationLedgerEntrySchema = object({
|
|
|
13655
13667
|
/** Why it is `blocked` or `held` (`dependency-failed`, `snapshot-refused`, …). */
|
|
13656
13668
|
reason: string().nullable(),
|
|
13657
13669
|
nodeId: string().nullable(),
|
|
13658
|
-
bootId: string().nullable()
|
|
13670
|
+
bootId: string().nullable(),
|
|
13671
|
+
/**
|
|
13672
|
+
* The catalogued meta of this id (description, body kind, store, `dependsOn`…),
|
|
13673
|
+
* joined by the engine from the catalogues it knows this boot. Absent when no
|
|
13674
|
+
* catalogue lists the id (a newer database).
|
|
13675
|
+
*/
|
|
13676
|
+
meta: MigrationMetaSchema.optional()
|
|
13659
13677
|
});
|
|
13660
13678
|
/** A catalogued migration that is not applied, with where it stands. */
|
|
13661
13679
|
var MigrationPendingEntrySchema = object({
|
|
@@ -19462,6 +19480,14 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
19462
19480
|
}
|
|
19463
19481
|
} }
|
|
19464
19482
|
},
|
|
19483
|
+
"device-runs": {
|
|
19484
|
+
scope: "device",
|
|
19485
|
+
noun: t("Runs", "Esecuzioni"),
|
|
19486
|
+
events: {
|
|
19487
|
+
onRunOpened: { notOperatorFacing: "the durable record of a run that the running-state start flip already announces" },
|
|
19488
|
+
onRunClosed: { notOperatorFacing: "the durable record of a run that the running-state finish flip already announces" }
|
|
19489
|
+
}
|
|
19490
|
+
},
|
|
19465
19491
|
update: {
|
|
19466
19492
|
scope: "device",
|
|
19467
19493
|
noun: t("Firmware update", "Aggiornamento firmware"),
|
|
@@ -46044,6 +46070,117 @@ function actuator(input) {
|
|
|
46044
46070
|
};
|
|
46045
46071
|
}
|
|
46046
46072
|
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
46073
|
+
var PowerSourceRefusalReasonSchema = _enum([
|
|
46074
|
+
"no-power-source",
|
|
46075
|
+
"switch-missing",
|
|
46076
|
+
"switch-offline",
|
|
46077
|
+
"switch-unknown",
|
|
46078
|
+
"restart-in-progress",
|
|
46079
|
+
"switch-call-failed"
|
|
46080
|
+
]);
|
|
46081
|
+
var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
|
|
46082
|
+
accepted: literal(false),
|
|
46083
|
+
reason: PowerSourceRefusalReasonSchema,
|
|
46084
|
+
/** One line for the operator, naming the switch. */
|
|
46085
|
+
message: string()
|
|
46086
|
+
})]);
|
|
46087
|
+
var PowerSourceInfoSchema = object({
|
|
46088
|
+
/** False when the device has no power source linked; the rest is then empty. */
|
|
46089
|
+
linked: boolean(),
|
|
46090
|
+
switchDeviceId: number().nullable(),
|
|
46091
|
+
switchName: string().nullable(),
|
|
46092
|
+
/** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
|
|
46093
|
+
switchOn: boolean().nullable(),
|
|
46094
|
+
switchOnline: boolean().nullable(),
|
|
46095
|
+
restartInProgress: boolean(),
|
|
46096
|
+
offSeconds: number().int()
|
|
46097
|
+
});
|
|
46098
|
+
/** The composed slice: the switch state the link mirrors, plus the stored off time. */
|
|
46099
|
+
var PowerSourceStateSchema = object({
|
|
46100
|
+
/** Null while the switch has not reported: unknown is never `false` (D393). */
|
|
46101
|
+
switchOn: boolean().nullable(),
|
|
46102
|
+
offSeconds: number().int(),
|
|
46103
|
+
lastFetchedAt: number()
|
|
46104
|
+
});
|
|
46105
|
+
var POWER_SOURCE_DEVICE_TYPES = [
|
|
46106
|
+
DeviceType.Gateway,
|
|
46107
|
+
DeviceType.Hub,
|
|
46108
|
+
DeviceType.Camera,
|
|
46109
|
+
DeviceType.Sensor,
|
|
46110
|
+
DeviceType.MediaPlayer,
|
|
46111
|
+
DeviceType.Vacuum,
|
|
46112
|
+
DeviceType.Generic,
|
|
46113
|
+
DeviceType.Washer,
|
|
46114
|
+
DeviceType.Dryer,
|
|
46115
|
+
DeviceType.Dishwasher,
|
|
46116
|
+
DeviceType.PetFountain,
|
|
46117
|
+
DeviceType.Fan,
|
|
46118
|
+
DeviceType.Humidifier,
|
|
46119
|
+
DeviceType.Climate,
|
|
46120
|
+
DeviceType.WaterHeater
|
|
46121
|
+
];
|
|
46122
|
+
var powerSourceCustomize = {
|
|
46123
|
+
version: 1,
|
|
46124
|
+
targets: [{
|
|
46125
|
+
id: "switch",
|
|
46126
|
+
cardinality: "scalar",
|
|
46127
|
+
vocabulary: {
|
|
46128
|
+
cap: "power-source",
|
|
46129
|
+
stateField: "switchOn"
|
|
46130
|
+
},
|
|
46131
|
+
deviceTypes: POWER_SOURCE_DEVICE_TYPES,
|
|
46132
|
+
apply: "add",
|
|
46133
|
+
path: "switchOn",
|
|
46134
|
+
sources: [{
|
|
46135
|
+
kind: "switch",
|
|
46136
|
+
transforms: [{ kind: "identity" }]
|
|
46137
|
+
}],
|
|
46138
|
+
companions: [{
|
|
46139
|
+
kind: "constant",
|
|
46140
|
+
path: "offSeconds",
|
|
46141
|
+
value: 10,
|
|
46142
|
+
when: "add"
|
|
46143
|
+
}, {
|
|
46144
|
+
kind: "clock",
|
|
46145
|
+
path: "lastFetchedAt",
|
|
46146
|
+
when: "always"
|
|
46147
|
+
}],
|
|
46148
|
+
sourceReport: { status: "assignment-status" }
|
|
46149
|
+
}]
|
|
46150
|
+
};
|
|
46151
|
+
var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
|
|
46152
|
+
var powerSourceCapability = {
|
|
46153
|
+
name: "power-source",
|
|
46154
|
+
scope: "device",
|
|
46155
|
+
mode: "singleton",
|
|
46156
|
+
deviceTypes: POWER_SOURCE_DEVICE_TYPES,
|
|
46157
|
+
methods: {
|
|
46158
|
+
getStatus: systemMethod(deviceInput$1, PowerSourceInfoSchema, { auth: "admin" }),
|
|
46159
|
+
powerOn: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
|
|
46160
|
+
kind: "mutation",
|
|
46161
|
+
auth: "admin"
|
|
46162
|
+
}),
|
|
46163
|
+
powerOff: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
|
|
46164
|
+
kind: "mutation",
|
|
46165
|
+
auth: "admin"
|
|
46166
|
+
}),
|
|
46167
|
+
forceRestart: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
|
|
46168
|
+
kind: "mutation",
|
|
46169
|
+
auth: "admin"
|
|
46170
|
+
})
|
|
46171
|
+
},
|
|
46172
|
+
runtimeState: PowerSourceStateSchema,
|
|
46173
|
+
customize: powerSourceCustomize,
|
|
46174
|
+
/**
|
|
46175
|
+
* Runtime-state durability: **session** — mirrored from the linked switch on
|
|
46176
|
+
* its next report; a restored value would outlive the reading it names.
|
|
46177
|
+
*
|
|
46178
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
46179
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
46180
|
+
*/
|
|
46181
|
+
durability: "session",
|
|
46182
|
+
history: "none"
|
|
46183
|
+
};
|
|
46047
46184
|
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
46048
46185
|
DeviceType.Camera;
|
|
46049
46186
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
@@ -47469,6 +47606,101 @@ method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly())
|
|
|
47469
47606
|
kind: "mutation",
|
|
47470
47607
|
auth: "admin"
|
|
47471
47608
|
});
|
|
47609
|
+
/**
|
|
47610
|
+
* device-runs - the durable record of ONE run of a device: a washing cycle, a
|
|
47611
|
+
* dishwasher cycle, later a mow or a clean (D992).
|
|
47612
|
+
*
|
|
47613
|
+
* A run is a DOCUMENT (opened at one instant, closed at another, carrying what
|
|
47614
|
+
* was measured over it), never a sample - device-history keeps the numbers over
|
|
47615
|
+
* time and its `device-runs` provider keeps these documents beside them, because
|
|
47616
|
+
* the energy of a run is a question about device-history's own series. The
|
|
47617
|
+
* record is written from the `running-state` flip on `DeviceStateChanged`; it
|
|
47618
|
+
* survives a restart (the open row is on disk) and a missed flip (boot compares
|
|
47619
|
+
* the open rows against the live snapshots).
|
|
47620
|
+
*
|
|
47621
|
+
* Every measurement is `number | null` and `null` means "could not be
|
|
47622
|
+
* measured", never `0` (D393). A run closed by the boot reconcile because the
|
|
47623
|
+
* device stopped while nobody was watching has `outcome: 'unknown'`.
|
|
47624
|
+
*/
|
|
47625
|
+
var DeviceRunKindSchema = _enum([
|
|
47626
|
+
"appliance",
|
|
47627
|
+
"mower",
|
|
47628
|
+
"vacuum"
|
|
47629
|
+
]);
|
|
47630
|
+
var DeviceRunStateSchema = _enum(["open", "closed"]);
|
|
47631
|
+
var DeviceRunOutcomeSchema = _enum([
|
|
47632
|
+
"completed",
|
|
47633
|
+
"aborted",
|
|
47634
|
+
"error",
|
|
47635
|
+
"unknown"
|
|
47636
|
+
]);
|
|
47637
|
+
/** What opened or closed the run. `reconcile` is the boot comparison against live state. */
|
|
47638
|
+
var DeviceRunSourceSchema = _enum([
|
|
47639
|
+
"running-state",
|
|
47640
|
+
"activity",
|
|
47641
|
+
"reconcile"
|
|
47642
|
+
]);
|
|
47643
|
+
/** How the energy of a run was obtained; `null` when it could not be. */
|
|
47644
|
+
var DeviceRunEnergyMethodSchema = _enum(["counter-delta", "history-integral"]);
|
|
47645
|
+
var DeviceRunPhaseSchema = object({
|
|
47646
|
+
phase: string(),
|
|
47647
|
+
at: number()
|
|
47648
|
+
});
|
|
47649
|
+
/** The kind-specific block; a later phase adds a branch, nothing else changes. */
|
|
47650
|
+
var DeviceRunDetailSchema = discriminatedUnion("kind", [object({
|
|
47651
|
+
kind: literal("appliance"),
|
|
47652
|
+
/** kWh used over the run. */
|
|
47653
|
+
energyKwh: number().nullable().meta(readingMeta("energy")),
|
|
47654
|
+
energyMethod: DeviceRunEnergyMethodSchema.nullable(),
|
|
47655
|
+
/** Highest power seen while the run was open. */
|
|
47656
|
+
peakW: number().nullable().meta(readingMeta("power")),
|
|
47657
|
+
/** Time-weighted mean power while the run was open. */
|
|
47658
|
+
avgW: number().nullable().meta(readingMeta("power")),
|
|
47659
|
+
/** The program the appliance said it ran when the run opened. */
|
|
47660
|
+
program: string().nullable(),
|
|
47661
|
+
remainingAtStartSec: number().nullable().meta(readingMeta("duration")),
|
|
47662
|
+
/** The last phase the device reported before the run closed. */
|
|
47663
|
+
finalPhase: string().nullable(),
|
|
47664
|
+
/**
|
|
47665
|
+
* The meter's energy counter when the run opened; `null` when the meter had
|
|
47666
|
+
* not said (or the run was opened late, by the boot reconcile). It lives in
|
|
47667
|
+
* the row so a run that outlives a restart still ends with `end - start`.
|
|
47668
|
+
*/
|
|
47669
|
+
energyStartKwh: number().nullable().meta(readingMeta("energy")),
|
|
47670
|
+
/** Milliseconds of power readings behind `avgW` - the weight a restart resumes the mean with. */
|
|
47671
|
+
powerObservedMs: number()
|
|
47672
|
+
})]);
|
|
47673
|
+
var DeviceRunSchema = object({
|
|
47674
|
+
/** `${deviceId}:${startedAt}`. */
|
|
47675
|
+
runId: string(),
|
|
47676
|
+
deviceId: number().int(),
|
|
47677
|
+
kind: DeviceRunKindSchema,
|
|
47678
|
+
state: DeviceRunStateSchema,
|
|
47679
|
+
startedAt: number(),
|
|
47680
|
+
endedAt: number().nullable(),
|
|
47681
|
+
durationMs: number().nullable(),
|
|
47682
|
+
outcome: DeviceRunOutcomeSchema.nullable(),
|
|
47683
|
+
startSource: DeviceRunSourceSchema,
|
|
47684
|
+
endSource: DeviceRunSourceSchema.nullable(),
|
|
47685
|
+
/** Where the device's running bit came from (`running-state.source`); `null` when it did not say. */
|
|
47686
|
+
runningSource: _enum(["native", "assigned"]).nullable(),
|
|
47687
|
+
phases: array(DeviceRunPhaseSchema),
|
|
47688
|
+
detail: DeviceRunDetailSchema
|
|
47689
|
+
});
|
|
47690
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, method(object({
|
|
47691
|
+
deviceId: number().int(),
|
|
47692
|
+
outcome: DeviceRunOutcomeSchema.optional(),
|
|
47693
|
+
atFrom: number().optional(),
|
|
47694
|
+
atTo: number().optional(),
|
|
47695
|
+
limit: number().int().positive().max(200).default(50),
|
|
47696
|
+
cursor: string().optional()
|
|
47697
|
+
}), object({
|
|
47698
|
+
runs: array(DeviceRunSchema).readonly(),
|
|
47699
|
+
nextCursor: string().nullable()
|
|
47700
|
+
})), method(object({
|
|
47701
|
+
deviceId: number().int(),
|
|
47702
|
+
runId: string()
|
|
47703
|
+
}), DeviceRunSchema.nullable()), method(object({ deviceId: number().int() }), DeviceRunSchema.nullable());
|
|
47472
47704
|
var DeviceCaStatusSchema = discriminatedUnion("state", [
|
|
47473
47705
|
object({ state: literal("absent") }),
|
|
47474
47706
|
object({
|
|
@@ -47604,8 +47836,8 @@ method(object({}), object({
|
|
|
47604
47836
|
});
|
|
47605
47837
|
var KeychainKeySourceSchema = object({
|
|
47606
47838
|
kind: _enum([
|
|
47607
|
-
"
|
|
47608
|
-
"previous-
|
|
47839
|
+
"mounted-file",
|
|
47840
|
+
"previous-mounted-file",
|
|
47609
47841
|
"platform",
|
|
47610
47842
|
"default-file"
|
|
47611
47843
|
]),
|
|
@@ -52101,7 +52333,8 @@ var PALETTE_ENTRY_IDS = [
|
|
|
52101
52333
|
"switch",
|
|
52102
52334
|
"siren",
|
|
52103
52335
|
"button",
|
|
52104
|
-
"doorbell"
|
|
52336
|
+
"doorbell",
|
|
52337
|
+
"appliance-cycle"
|
|
52105
52338
|
];
|
|
52106
52339
|
var AUDIO_ENTRY_ID = "audio";
|
|
52107
52340
|
/** Six rungs, quiet → loud. The opaque end is the entry's hex. */
|
|
@@ -52172,7 +52405,8 @@ var CAMSTACK_HEX = {
|
|
|
52172
52405
|
switch: "#7a812a",
|
|
52173
52406
|
siren: "#ac5d7f",
|
|
52174
52407
|
button: "#b276cd",
|
|
52175
|
-
doorbell: "#0087ab"
|
|
52408
|
+
doorbell: "#0087ab",
|
|
52409
|
+
"appliance-cycle": "#2a8c8c"
|
|
52176
52410
|
};
|
|
52177
52411
|
var CAMSTACK_FALLBACK = [
|
|
52178
52412
|
"#b34dc7",
|
|
@@ -52237,7 +52471,8 @@ var HIGH_CONTRAST_HEX = {
|
|
|
52237
52471
|
switch: "#d05259",
|
|
52238
52472
|
siren: "#cd67b3",
|
|
52239
52473
|
button: "#c9746a",
|
|
52240
|
-
doorbell: "#338eeb"
|
|
52474
|
+
doorbell: "#338eeb",
|
|
52475
|
+
"appliance-cycle": "#00848a"
|
|
52241
52476
|
};
|
|
52242
52477
|
var HIGH_CONTRAST_FALLBACK = [
|
|
52243
52478
|
"#817f3b",
|
|
@@ -52302,7 +52537,8 @@ var OKABE_ITO_HEX = {
|
|
|
52302
52537
|
switch: "#ad2c4e",
|
|
52303
52538
|
siren: "#348e08",
|
|
52304
52539
|
button: "#d27303",
|
|
52305
|
-
doorbell: "#55770f"
|
|
52540
|
+
doorbell: "#55770f",
|
|
52541
|
+
"appliance-cycle": "#00737d"
|
|
52306
52542
|
};
|
|
52307
52543
|
var OKABE_ITO_FALLBACK = [
|
|
52308
52544
|
"#9a3784",
|
|
@@ -52511,6 +52747,7 @@ sub("switch", "control", "control", "switch", "Switch");
|
|
|
52511
52747
|
sub("siren", "control", "control", "siren", "Siren");
|
|
52512
52748
|
sub("button", "control", "control", "button", "Button");
|
|
52513
52749
|
sub("doorbell", "control", "control", "doorbell", "Doorbell");
|
|
52750
|
+
sub("appliance-cycle", "control", "control", "switch", "Appliance cycle");
|
|
52514
52751
|
for (const l of AUDIO_MACRO_LABELS) {
|
|
52515
52752
|
const kind = `audio-${l.id}`;
|
|
52516
52753
|
if (entries.has(kind)) continue;
|
|
@@ -61142,7 +61379,8 @@ var CAP_TO_KIND = {
|
|
|
61142
61379
|
cover: "cover",
|
|
61143
61380
|
switch: "switch",
|
|
61144
61381
|
button: "button",
|
|
61145
|
-
doorbell: "doorbell"
|
|
61382
|
+
doorbell: "doorbell",
|
|
61383
|
+
"running-state": "appliance-cycle"
|
|
61146
61384
|
};
|
|
61147
61385
|
function buildDescriptor(capName, kind) {
|
|
61148
61386
|
const t = EVENT_TAXONOMY[kind];
|
|
@@ -64272,10 +64510,7 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
64272
64510
|
}), InstallPackageResultSchema, {
|
|
64273
64511
|
kind: "mutation",
|
|
64274
64512
|
auth: "admin"
|
|
64275
|
-
}), method(object({
|
|
64276
|
-
kind: "mutation",
|
|
64277
|
-
auth: "admin"
|
|
64278
|
-
}), method(_void(), boolean()), method(_void(), array(unknown()).readonly()), method(object({
|
|
64513
|
+
}), method(object({
|
|
64279
64514
|
packageName: string().min(1),
|
|
64280
64515
|
nodeId: string().optional(),
|
|
64281
64516
|
everywhere: boolean().optional()
|
|
@@ -65536,19 +65771,19 @@ var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status:
|
|
|
65536
65771
|
reason: _enum(["unknown-template", "not-a-media-player"]),
|
|
65537
65772
|
detail: string()
|
|
65538
65773
|
})]);
|
|
65539
|
-
var deviceInput
|
|
65774
|
+
var deviceInput = object({ deviceId: number().int().nonnegative() });
|
|
65540
65775
|
DeviceType.MediaPlayer;
|
|
65541
|
-
method(deviceInput
|
|
65776
|
+
method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
|
|
65542
65777
|
kind: "mutation",
|
|
65543
65778
|
auth: "admin"
|
|
65544
|
-
}), method(deviceInput
|
|
65779
|
+
}), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
|
|
65545
65780
|
role: RemoteRoleSchema,
|
|
65546
65781
|
/** Sends in a row (volume steps). */
|
|
65547
65782
|
repeat: number().int().min(1).max(50).default(1)
|
|
65548
65783
|
}), RemoteSendResultSchema, {
|
|
65549
65784
|
kind: "mutation",
|
|
65550
65785
|
auth: "protected"
|
|
65551
|
-
}), method(deviceInput
|
|
65786
|
+
}), method(deviceInput.extend({
|
|
65552
65787
|
command: RemoteMediaCommandSchema,
|
|
65553
65788
|
muted: boolean().optional(),
|
|
65554
65789
|
source: string().optional(),
|
|
@@ -69922,117 +70157,6 @@ var lockControlCapability = {
|
|
|
69922
70157
|
* whether persisting is worth a SQLite commit. */
|
|
69923
70158
|
volatileStateFields: ["lastChangedAt"]
|
|
69924
70159
|
};
|
|
69925
|
-
var PowerSourceRefusalReasonSchema = _enum([
|
|
69926
|
-
"no-power-source",
|
|
69927
|
-
"switch-missing",
|
|
69928
|
-
"switch-offline",
|
|
69929
|
-
"switch-unknown",
|
|
69930
|
-
"restart-in-progress",
|
|
69931
|
-
"switch-call-failed"
|
|
69932
|
-
]);
|
|
69933
|
-
var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
|
|
69934
|
-
accepted: literal(false),
|
|
69935
|
-
reason: PowerSourceRefusalReasonSchema,
|
|
69936
|
-
/** One line for the operator, naming the switch. */
|
|
69937
|
-
message: string()
|
|
69938
|
-
})]);
|
|
69939
|
-
var PowerSourceInfoSchema = object({
|
|
69940
|
-
/** False when the device has no power source linked; the rest is then empty. */
|
|
69941
|
-
linked: boolean(),
|
|
69942
|
-
switchDeviceId: number().nullable(),
|
|
69943
|
-
switchName: string().nullable(),
|
|
69944
|
-
/** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
|
|
69945
|
-
switchOn: boolean().nullable(),
|
|
69946
|
-
switchOnline: boolean().nullable(),
|
|
69947
|
-
restartInProgress: boolean(),
|
|
69948
|
-
offSeconds: number().int()
|
|
69949
|
-
});
|
|
69950
|
-
/** The composed slice: the switch state the link mirrors, plus the stored off time. */
|
|
69951
|
-
var PowerSourceStateSchema = object({
|
|
69952
|
-
/** Null while the switch has not reported: unknown is never `false` (D393). */
|
|
69953
|
-
switchOn: boolean().nullable(),
|
|
69954
|
-
offSeconds: number().int(),
|
|
69955
|
-
lastFetchedAt: number()
|
|
69956
|
-
});
|
|
69957
|
-
var POWER_SOURCE_DEVICE_TYPES = [
|
|
69958
|
-
DeviceType.Gateway,
|
|
69959
|
-
DeviceType.Hub,
|
|
69960
|
-
DeviceType.Camera,
|
|
69961
|
-
DeviceType.Sensor,
|
|
69962
|
-
DeviceType.MediaPlayer,
|
|
69963
|
-
DeviceType.Vacuum,
|
|
69964
|
-
DeviceType.Generic,
|
|
69965
|
-
DeviceType.Washer,
|
|
69966
|
-
DeviceType.Dryer,
|
|
69967
|
-
DeviceType.Dishwasher,
|
|
69968
|
-
DeviceType.PetFountain,
|
|
69969
|
-
DeviceType.Fan,
|
|
69970
|
-
DeviceType.Humidifier,
|
|
69971
|
-
DeviceType.Climate,
|
|
69972
|
-
DeviceType.WaterHeater
|
|
69973
|
-
];
|
|
69974
|
-
var powerSourceCustomize = {
|
|
69975
|
-
version: 1,
|
|
69976
|
-
targets: [{
|
|
69977
|
-
id: "switch",
|
|
69978
|
-
cardinality: "scalar",
|
|
69979
|
-
vocabulary: {
|
|
69980
|
-
cap: "power-source",
|
|
69981
|
-
stateField: "switchOn"
|
|
69982
|
-
},
|
|
69983
|
-
deviceTypes: POWER_SOURCE_DEVICE_TYPES,
|
|
69984
|
-
apply: "add",
|
|
69985
|
-
path: "switchOn",
|
|
69986
|
-
sources: [{
|
|
69987
|
-
kind: "switch",
|
|
69988
|
-
transforms: [{ kind: "identity" }]
|
|
69989
|
-
}],
|
|
69990
|
-
companions: [{
|
|
69991
|
-
kind: "constant",
|
|
69992
|
-
path: "offSeconds",
|
|
69993
|
-
value: 10,
|
|
69994
|
-
when: "add"
|
|
69995
|
-
}, {
|
|
69996
|
-
kind: "clock",
|
|
69997
|
-
path: "lastFetchedAt",
|
|
69998
|
-
when: "always"
|
|
69999
|
-
}],
|
|
70000
|
-
sourceReport: { status: "assignment-status" }
|
|
70001
|
-
}]
|
|
70002
|
-
};
|
|
70003
|
-
var deviceInput = object({ deviceId: number().int().nonnegative() });
|
|
70004
|
-
var powerSourceCapability = {
|
|
70005
|
-
name: "power-source",
|
|
70006
|
-
scope: "device",
|
|
70007
|
-
mode: "singleton",
|
|
70008
|
-
deviceTypes: POWER_SOURCE_DEVICE_TYPES,
|
|
70009
|
-
methods: {
|
|
70010
|
-
getStatus: systemMethod(deviceInput, PowerSourceInfoSchema, { auth: "admin" }),
|
|
70011
|
-
powerOn: systemMethod(deviceInput, PowerSourceActionResultSchema, {
|
|
70012
|
-
kind: "mutation",
|
|
70013
|
-
auth: "admin"
|
|
70014
|
-
}),
|
|
70015
|
-
powerOff: systemMethod(deviceInput, PowerSourceActionResultSchema, {
|
|
70016
|
-
kind: "mutation",
|
|
70017
|
-
auth: "admin"
|
|
70018
|
-
}),
|
|
70019
|
-
forceRestart: systemMethod(deviceInput, PowerSourceActionResultSchema, {
|
|
70020
|
-
kind: "mutation",
|
|
70021
|
-
auth: "admin"
|
|
70022
|
-
})
|
|
70023
|
-
},
|
|
70024
|
-
runtimeState: PowerSourceStateSchema,
|
|
70025
|
-
customize: powerSourceCustomize,
|
|
70026
|
-
/**
|
|
70027
|
-
* Runtime-state durability: **session** — mirrored from the linked switch on
|
|
70028
|
-
* its next report; a restored value would outlive the reading it names.
|
|
70029
|
-
*
|
|
70030
|
-
* See `RuntimeStateDurability`. Enforced by
|
|
70031
|
-
* `scripts/check-runtime-state-durability.ts`.
|
|
70032
|
-
*/
|
|
70033
|
-
durability: "session",
|
|
70034
|
-
history: "none"
|
|
70035
|
-
};
|
|
70036
70160
|
/**
|
|
70037
70161
|
* A monotonic total between resets (D944). Energy uses `power-meter.energy`
|
|
70038
70162
|
* so dashboards keep one series; every other instantaneous reading lands here.
|
|
@@ -73574,6 +73698,10 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
73574
73698
|
/** Generic Customize target for the running boolean (D936). */
|
|
73575
73699
|
var runningCustomize = {
|
|
73576
73700
|
version: 1,
|
|
73701
|
+
overridable: [{
|
|
73702
|
+
path: "running",
|
|
73703
|
+
by: "running"
|
|
73704
|
+
}],
|
|
73577
73705
|
targets: [{
|
|
73578
73706
|
id: "running",
|
|
73579
73707
|
cardinality: "scalar",
|
|
@@ -73631,7 +73759,7 @@ var runningCustomize = {
|
|
|
73631
73759
|
kind: "constant",
|
|
73632
73760
|
path: "phase",
|
|
73633
73761
|
value: null,
|
|
73634
|
-
when: "
|
|
73762
|
+
when: "add"
|
|
73635
73763
|
},
|
|
73636
73764
|
{
|
|
73637
73765
|
kind: "clock",
|
|
@@ -76941,7 +77069,7 @@ var ExternalIdentityKeySchema = object({
|
|
|
76941
77069
|
provider: string().min(1),
|
|
76942
77070
|
subject: string().min(1)
|
|
76943
77071
|
});
|
|
76944
|
-
method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserInputSchema, UserSummarySchema, {
|
|
77072
|
+
method(_void(), array(UserSummarySchema), { auth: "admin" }), method(_void(), object({ defaultPasswordInUse: boolean() }), { auth: "admin" }), method(CreateUserInputSchema, UserSummarySchema, {
|
|
76945
77073
|
kind: "mutation",
|
|
76946
77074
|
auth: "admin",
|
|
76947
77075
|
access: "create"
|
|
@@ -80280,13 +80408,6 @@ Object.freeze({
|
|
|
80280
80408
|
access: "view",
|
|
80281
80409
|
role: "admin"
|
|
80282
80410
|
},
|
|
80283
|
-
"addons.installFromWorkspace": {
|
|
80284
|
-
capName: "addons",
|
|
80285
|
-
capScope: "system",
|
|
80286
|
-
addonId: null,
|
|
80287
|
-
access: "create",
|
|
80288
|
-
role: "admin"
|
|
80289
|
-
},
|
|
80290
80411
|
"addons.installPackage": {
|
|
80291
80412
|
capName: "addons",
|
|
80292
80413
|
capScope: "system",
|
|
@@ -80294,13 +80415,6 @@ Object.freeze({
|
|
|
80294
80415
|
access: "create",
|
|
80295
80416
|
role: "admin"
|
|
80296
80417
|
},
|
|
80297
|
-
"addons.isWorkspaceAvailable": {
|
|
80298
|
-
capName: "addons",
|
|
80299
|
-
capScope: "system",
|
|
80300
|
-
addonId: null,
|
|
80301
|
-
access: "view",
|
|
80302
|
-
role: "admin"
|
|
80303
|
-
},
|
|
80304
80418
|
"addons.list": {
|
|
80305
80419
|
capName: "addons",
|
|
80306
80420
|
capScope: "system",
|
|
@@ -80350,13 +80464,6 @@ Object.freeze({
|
|
|
80350
80464
|
access: "view",
|
|
80351
80465
|
role: "admin"
|
|
80352
80466
|
},
|
|
80353
|
-
"addons.listWorkspacePackages": {
|
|
80354
|
-
capName: "addons",
|
|
80355
|
-
capScope: "system",
|
|
80356
|
-
addonId: null,
|
|
80357
|
-
access: "view",
|
|
80358
|
-
role: "admin"
|
|
80359
|
-
},
|
|
80360
80467
|
"addons.onAddonLogs": {
|
|
80361
80468
|
capName: "addons",
|
|
80362
80469
|
capScope: "system",
|
|
@@ -83024,6 +83131,27 @@ Object.freeze({
|
|
|
83024
83131
|
access: "create",
|
|
83025
83132
|
role: "admin"
|
|
83026
83133
|
},
|
|
83134
|
+
"deviceRuns.getCurrentRun": {
|
|
83135
|
+
capName: "device-runs",
|
|
83136
|
+
capScope: "device",
|
|
83137
|
+
addonId: null,
|
|
83138
|
+
access: "view",
|
|
83139
|
+
role: "viewer"
|
|
83140
|
+
},
|
|
83141
|
+
"deviceRuns.getRun": {
|
|
83142
|
+
capName: "device-runs",
|
|
83143
|
+
capScope: "device",
|
|
83144
|
+
addonId: null,
|
|
83145
|
+
access: "view",
|
|
83146
|
+
role: "viewer"
|
|
83147
|
+
},
|
|
83148
|
+
"deviceRuns.listRuns": {
|
|
83149
|
+
capName: "device-runs",
|
|
83150
|
+
capScope: "device",
|
|
83151
|
+
addonId: null,
|
|
83152
|
+
access: "view",
|
|
83153
|
+
role: "viewer"
|
|
83154
|
+
},
|
|
83027
83155
|
"deviceState.claimFields": {
|
|
83028
83156
|
capName: "device-state",
|
|
83029
83157
|
capScope: "system",
|
|
@@ -89737,6 +89865,13 @@ Object.freeze({
|
|
|
89737
89865
|
access: "view",
|
|
89738
89866
|
role: "admin"
|
|
89739
89867
|
},
|
|
89868
|
+
"userManagement.getAdminBootstrapStatus": {
|
|
89869
|
+
capName: "user-management",
|
|
89870
|
+
capScope: "system",
|
|
89871
|
+
addonId: null,
|
|
89872
|
+
access: "view",
|
|
89873
|
+
role: "admin"
|
|
89874
|
+
},
|
|
89740
89875
|
"userManagement.getTotpStatus": {
|
|
89741
89876
|
capName: "user-management",
|
|
89742
89877
|
capScope: "system",
|
|
@@ -91222,6 +91357,21 @@ Object.freeze({
|
|
|
91222
91357
|
form: "single",
|
|
91223
91358
|
optional: false
|
|
91224
91359
|
}],
|
|
91360
|
+
"deviceRuns.getCurrentRun": [{
|
|
91361
|
+
name: "deviceId",
|
|
91362
|
+
form: "single",
|
|
91363
|
+
optional: false
|
|
91364
|
+
}],
|
|
91365
|
+
"deviceRuns.getRun": [{
|
|
91366
|
+
name: "deviceId",
|
|
91367
|
+
form: "single",
|
|
91368
|
+
optional: false
|
|
91369
|
+
}],
|
|
91370
|
+
"deviceRuns.listRuns": [{
|
|
91371
|
+
name: "deviceId",
|
|
91372
|
+
form: "single",
|
|
91373
|
+
optional: false
|
|
91374
|
+
}],
|
|
91225
91375
|
"deviceState.claimFields": [{
|
|
91226
91376
|
name: "deviceId",
|
|
91227
91377
|
form: "single",
|
|
@@ -93704,13 +93854,114 @@ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
|
|
|
93704
93854
|
*
|
|
93705
93855
|
* Pure, RN-safe: the viewer imports the support rule from here.
|
|
93706
93856
|
*/
|
|
93857
|
+
/**
|
|
93858
|
+
* Control caps that still have a raise and a clear an operator names: an
|
|
93859
|
+
* appliance cycle raises when it STARTS and clears when it FINISHES. Kept out
|
|
93860
|
+
* of `SOURCE_CAP_ACTIVE_FIELD` on purpose — that table also makes a device a
|
|
93861
|
+
* camera-sensor / recorder-trigger source, and a dishwasher is neither.
|
|
93862
|
+
*/
|
|
93863
|
+
var CYCLE_RAISED_FIELD_BY_CAP = { "running-state": "running" };
|
|
93707
93864
|
/** Event kind → the boolean field of its cap slice that means "raised". */
|
|
93708
93865
|
var NC_SENSOR_RAISED_FIELD_BY_KIND = Object.freeze(Object.fromEntries(Object.entries(EVENT_KIND_BY_CAP).flatMap(([capName, descriptor]) => {
|
|
93866
|
+
const cycleField = CYCLE_RAISED_FIELD_BY_CAP[capName];
|
|
93867
|
+
if (cycleField !== void 0) return [[descriptor.kind, cycleField]];
|
|
93709
93868
|
const field = SOURCE_CAP_ACTIVE_FIELD[capName];
|
|
93710
93869
|
if (field === void 0 || descriptor.category !== "sensor") return [];
|
|
93711
93870
|
return [[descriptor.kind, field]];
|
|
93712
93871
|
})));
|
|
93713
93872
|
Object.freeze(Object.keys(NC_SENSOR_RAISED_FIELD_BY_KIND));
|
|
93873
|
+
Object.freeze({
|
|
93874
|
+
contact: {
|
|
93875
|
+
starts: {
|
|
93876
|
+
en: "opened",
|
|
93877
|
+
it: "si apre"
|
|
93878
|
+
},
|
|
93879
|
+
finishes: {
|
|
93880
|
+
en: "closed",
|
|
93881
|
+
it: "si chiude"
|
|
93882
|
+
}
|
|
93883
|
+
},
|
|
93884
|
+
"motion-sensor": {
|
|
93885
|
+
starts: {
|
|
93886
|
+
en: "motion detected",
|
|
93887
|
+
it: "movimento rilevato"
|
|
93888
|
+
},
|
|
93889
|
+
finishes: {
|
|
93890
|
+
en: "motion stopped",
|
|
93891
|
+
it: "movimento terminato"
|
|
93892
|
+
}
|
|
93893
|
+
},
|
|
93894
|
+
smoke: {
|
|
93895
|
+
starts: {
|
|
93896
|
+
en: "smoke detected",
|
|
93897
|
+
it: "fumo rilevato"
|
|
93898
|
+
},
|
|
93899
|
+
finishes: {
|
|
93900
|
+
en: "smoke gone",
|
|
93901
|
+
it: "fumo scomparso"
|
|
93902
|
+
}
|
|
93903
|
+
},
|
|
93904
|
+
flood: {
|
|
93905
|
+
starts: {
|
|
93906
|
+
en: "water detected",
|
|
93907
|
+
it: "acqua rilevata"
|
|
93908
|
+
},
|
|
93909
|
+
finishes: {
|
|
93910
|
+
en: "dry again",
|
|
93911
|
+
it: "di nuovo asciutto"
|
|
93912
|
+
}
|
|
93913
|
+
},
|
|
93914
|
+
gas: {
|
|
93915
|
+
starts: {
|
|
93916
|
+
en: "gas detected",
|
|
93917
|
+
it: "gas rilevato"
|
|
93918
|
+
},
|
|
93919
|
+
finishes: {
|
|
93920
|
+
en: "gas gone",
|
|
93921
|
+
it: "gas scomparso"
|
|
93922
|
+
}
|
|
93923
|
+
},
|
|
93924
|
+
"carbon-monoxide": {
|
|
93925
|
+
starts: {
|
|
93926
|
+
en: "carbon monoxide detected",
|
|
93927
|
+
it: "monossido rilevato"
|
|
93928
|
+
},
|
|
93929
|
+
finishes: {
|
|
93930
|
+
en: "carbon monoxide gone",
|
|
93931
|
+
it: "monossido scomparso"
|
|
93932
|
+
}
|
|
93933
|
+
},
|
|
93934
|
+
vibration: {
|
|
93935
|
+
starts: {
|
|
93936
|
+
en: "vibration detected",
|
|
93937
|
+
it: "vibrazione rilevata"
|
|
93938
|
+
},
|
|
93939
|
+
finishes: {
|
|
93940
|
+
en: "vibration stopped",
|
|
93941
|
+
it: "vibrazione terminata"
|
|
93942
|
+
}
|
|
93943
|
+
},
|
|
93944
|
+
tamper: {
|
|
93945
|
+
starts: {
|
|
93946
|
+
en: "tampered with",
|
|
93947
|
+
it: "manomesso"
|
|
93948
|
+
},
|
|
93949
|
+
finishes: {
|
|
93950
|
+
en: "tamper cleared",
|
|
93951
|
+
it: "manomissione rientrata"
|
|
93952
|
+
}
|
|
93953
|
+
},
|
|
93954
|
+
"appliance-cycle": {
|
|
93955
|
+
starts: {
|
|
93956
|
+
en: "the cycle started",
|
|
93957
|
+
it: "il ciclo parte"
|
|
93958
|
+
},
|
|
93959
|
+
finishes: {
|
|
93960
|
+
en: "the cycle finished",
|
|
93961
|
+
it: "il ciclo è terminato"
|
|
93962
|
+
}
|
|
93963
|
+
}
|
|
93964
|
+
});
|
|
93714
93965
|
object({
|
|
93715
93966
|
phase: _enum(["raised", "resolved"]),
|
|
93716
93967
|
episodeId: string().min(1),
|
|
@@ -93917,6 +94168,10 @@ var STATE_SUMMARY_VARS = [
|
|
|
93917
94168
|
[...RULE_TEXT],
|
|
93918
94169
|
[...RULE_TEXT],
|
|
93919
94170
|
[...RULE_TEXT],
|
|
94171
|
+
[...RULE_TEXT],
|
|
94172
|
+
[...RULE_TEXT],
|
|
94173
|
+
[...RULE_TEXT],
|
|
94174
|
+
[...RULE_TEXT],
|
|
93920
94175
|
[...RULE_BODY_ONLY],
|
|
93921
94176
|
[...RULE_TEXT],
|
|
93922
94177
|
([...RULE_TEXT], [...DEVICE_EVENTS]),
|
|
@@ -93934,6 +94189,7 @@ var STATE_SUMMARY_VARS = [
|
|
|
93934
94189
|
[...RULE_TEXT],
|
|
93935
94190
|
[...RULE_TEXT],
|
|
93936
94191
|
[...RULE_TEXT],
|
|
94192
|
+
[...RULE_TEXT],
|
|
93937
94193
|
([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
|
|
93938
94194
|
[...RULE_TEXT],
|
|
93939
94195
|
[...RULE_TEXT],
|
|
@@ -94178,6 +94434,7 @@ new Set([
|
|
|
94178
94434
|
"siren",
|
|
94179
94435
|
"button",
|
|
94180
94436
|
"doorbell",
|
|
94437
|
+
"appliance-cycle",
|
|
94181
94438
|
"audio-speech",
|
|
94182
94439
|
"audio-scream",
|
|
94183
94440
|
"audio-crying",
|
|
@@ -103487,22 +103744,26 @@ var VeluxClientRegistry = class {
|
|
|
103487
103744
|
};
|
|
103488
103745
|
//#endregion
|
|
103489
103746
|
//#region src/klf-probe.ts
|
|
103490
|
-
/** The gateway's TLS API port. */
|
|
103491
|
-
var KLF_PORT = 51200;
|
|
103492
103747
|
/**
|
|
103493
|
-
* Defaults add up, worst case, to
|
|
103494
|
-
* `CONNECTION_TEST_TIMEOUT_MS` ceiling
|
|
103495
|
-
* here instead of the
|
|
103748
|
+
* Defaults add up, worst case, to 12 + 3 + 1.5 + 1.5 = 18 s, which is the
|
|
103749
|
+
* wizard's `CONNECTION_TEST_TIMEOUT_MS` ceiling (20 s) minus the 2 s margin of
|
|
103750
|
+
* `DEFAULT_TEST_DEADLINE_MS`, so a stuck gateway is named here instead of the
|
|
103751
|
+
* wizard giving up unnamed. The handshake gets 12 s because a real KLF-200 needs
|
|
103752
|
+
* about 4.2 s for ONE handshake (TLSv1.2, DHE-RSA-AES256-SHA256 on a weak CPU).
|
|
103753
|
+
*
|
|
103754
|
+
* A probe opens exactly ONE connection: the gateway frees a closed slot very
|
|
103755
|
+
* slowly (measured 2026-11-01: a bare TCP connect and close before the TLS connect
|
|
103756
|
+
* left the real session without a handshake for 20 s), so no pre-check connects first.
|
|
103496
103757
|
*/
|
|
103497
103758
|
var DEFAULT_KLF_PROBE_TIMEOUTS_MS = {
|
|
103498
|
-
|
|
103499
|
-
|
|
103500
|
-
version:
|
|
103501
|
-
logout:
|
|
103759
|
+
tls: 12e3,
|
|
103760
|
+
password: 3e3,
|
|
103761
|
+
version: 1500,
|
|
103762
|
+
logout: 1500
|
|
103502
103763
|
};
|
|
103503
103764
|
var PHASE_TEXT = {
|
|
103504
|
-
|
|
103505
|
-
|
|
103765
|
+
tls: "did not accept a connection or complete the TLS handshake on port 51200",
|
|
103766
|
+
password: "did not answer the password",
|
|
103506
103767
|
version: "did not answer the version request",
|
|
103507
103768
|
logout: "did not close the session"
|
|
103508
103769
|
};
|
|
@@ -103529,26 +103790,43 @@ async function withDeadline(work, ms, onTimeout) {
|
|
|
103529
103790
|
clearTimeout(timer);
|
|
103530
103791
|
}
|
|
103531
103792
|
}
|
|
103532
|
-
/**
|
|
103533
|
-
|
|
103534
|
-
|
|
103535
|
-
|
|
103536
|
-
|
|
103537
|
-
|
|
103538
|
-
|
|
103539
|
-
|
|
103540
|
-
|
|
103541
|
-
|
|
103542
|
-
|
|
103543
|
-
|
|
103544
|
-
|
|
103545
|
-
|
|
103546
|
-
|
|
103547
|
-
|
|
103548
|
-
|
|
103549
|
-
|
|
103550
|
-
|
|
103793
|
+
/** How often the login watcher checks whether the handshake has finished. */
|
|
103794
|
+
var PHASE_POLL_MS = 20;
|
|
103795
|
+
/**
|
|
103796
|
+
* The library's `loginAsync` runs the TLS handshake and the password answer as one
|
|
103797
|
+
* call. `KLF200SocketProtocol` appears when the handshake is done and the password
|
|
103798
|
+
* is on its way, so watching it splits the call into two bounded, named steps.
|
|
103799
|
+
*/
|
|
103800
|
+
async function loginInPhases(connection, host, password, limits) {
|
|
103801
|
+
let handshakeDone = false;
|
|
103802
|
+
let passwordTimer;
|
|
103803
|
+
let tlsTimer;
|
|
103804
|
+
let poll;
|
|
103805
|
+
const tlsError = () => new KlfProbeTimeoutError("tls", host, limits.tls);
|
|
103806
|
+
const passwordError = () => new KlfProbeTimeoutError("password", host, limits.password);
|
|
103807
|
+
const bounds = new Promise((_resolve, reject) => {
|
|
103808
|
+
tlsTimer = setTimeout(() => reject(tlsError()), limits.tls);
|
|
103809
|
+
poll = setInterval(() => {
|
|
103810
|
+
if (handshakeDone || connection.KLF200SocketProtocol === void 0) return;
|
|
103811
|
+
handshakeDone = true;
|
|
103812
|
+
clearTimeout(tlsTimer);
|
|
103813
|
+
clearInterval(poll);
|
|
103814
|
+
passwordTimer = setTimeout(() => reject(passwordError()), limits.password);
|
|
103815
|
+
}, PHASE_POLL_MS);
|
|
103551
103816
|
});
|
|
103817
|
+
const libraryS = (limits.tls + limits.password) / 1e3;
|
|
103818
|
+
try {
|
|
103819
|
+
await Promise.race([connection.loginAsync(password, libraryS), bounds]);
|
|
103820
|
+
} catch (err) {
|
|
103821
|
+
if (err instanceof KlfProbeTimeoutError) throw err;
|
|
103822
|
+
if (/^timeout$/i.test(errMsg(err)) || err instanceof Error && err.name === "TimeoutError") throw handshakeDone ? passwordError() : tlsError();
|
|
103823
|
+
throw err;
|
|
103824
|
+
} finally {
|
|
103825
|
+
clearTimeout(tlsTimer);
|
|
103826
|
+
clearTimeout(passwordTimer);
|
|
103827
|
+
clearInterval(poll);
|
|
103828
|
+
bounds.catch(() => void 0);
|
|
103829
|
+
}
|
|
103552
103830
|
}
|
|
103553
103831
|
/**
|
|
103554
103832
|
* Opens ONE session, authenticates, reads the firmware version and closes the
|
|
@@ -103561,15 +103839,13 @@ async function probeKlfGateway(options) {
|
|
|
103561
103839
|
...DEFAULT_KLF_PROBE_TIMEOUTS_MS,
|
|
103562
103840
|
...options.timeoutsMs
|
|
103563
103841
|
};
|
|
103564
|
-
await tcpReachable(options.host, limits.tcp);
|
|
103565
103842
|
const connection = options.tls === void 0 ? new Connection(options.host) : new Connection(options.host, options.tls);
|
|
103566
|
-
const loginError = () => new KlfProbeTimeoutError("login", options.host, limits.login);
|
|
103567
103843
|
try {
|
|
103568
103844
|
try {
|
|
103569
|
-
await
|
|
103845
|
+
await loginInPhases(connection, options.host, options.password, limits);
|
|
103570
103846
|
} catch (err) {
|
|
103571
103847
|
if (err instanceof KlfProbeTimeoutError) throw err;
|
|
103572
|
-
if (
|
|
103848
|
+
if (err instanceof Error && typeof Reflect.get(err, "code") === "string") throw err;
|
|
103573
103849
|
throw loginFailure(err);
|
|
103574
103850
|
}
|
|
103575
103851
|
try {
|