@camstack/addon-provider-homematic 1.2.131 → 1.2.133
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/dist/addon.js +413 -136
- package/dist/addon.mjs +413 -136
- package/package.json +1 -1
package/dist/addon.mjs
CHANGED
|
@@ -5387,7 +5387,7 @@ var ZodIssueCode = {
|
|
|
5387
5387
|
var ZodFirstPartyTypeKind;
|
|
5388
5388
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5389
5389
|
//#endregion
|
|
5390
|
-
//#region ../types/dist/sleep-
|
|
5390
|
+
//#region ../types/dist/sleep-CI0n5D44.mjs
|
|
5391
5391
|
/**
|
|
5392
5392
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5393
5393
|
* window to float samples (D455).
|
|
@@ -9393,6 +9393,16 @@ var CompositionSchema = object({
|
|
|
9393
9393
|
seen.add(feature.cap);
|
|
9394
9394
|
});
|
|
9395
9395
|
});
|
|
9396
|
+
var NodeColorIdSchema = _enum([
|
|
9397
|
+
"node-a",
|
|
9398
|
+
"node-b",
|
|
9399
|
+
"node-c",
|
|
9400
|
+
"node-d",
|
|
9401
|
+
"node-e",
|
|
9402
|
+
"node-f",
|
|
9403
|
+
"node-g",
|
|
9404
|
+
"node-h"
|
|
9405
|
+
]);
|
|
9396
9406
|
new Set([
|
|
9397
9407
|
"track",
|
|
9398
9408
|
"face",
|
|
@@ -24459,24 +24469,69 @@ var RetrainFrameListSchema = object({
|
|
|
24459
24469
|
/** What the page pre-selects — the native key frame when one survives. */
|
|
24460
24470
|
autoPickMediaId: number().int().optional()
|
|
24461
24471
|
});
|
|
24472
|
+
/** Exclusive partition of a corpus copy's annotation progress (design §4.2). */
|
|
24473
|
+
var RetrainFrameWorkStateSchema = _enum([
|
|
24474
|
+
"unannotated",
|
|
24475
|
+
"annotated",
|
|
24476
|
+
"complete"
|
|
24477
|
+
]);
|
|
24478
|
+
/**
|
|
24479
|
+
* Filters for paginated corpus list, KPI, and matching export (design §4.4).
|
|
24480
|
+
* Every narrowing field is ANDed; omitted fields impose no constraint.
|
|
24481
|
+
*/
|
|
24482
|
+
var RetrainCorpusFilterSchema = object({
|
|
24483
|
+
workState: RetrainFrameWorkStateSchema.optional(),
|
|
24484
|
+
deviceIds: array(number()).max(500).optional(),
|
|
24485
|
+
/** When set, only frames in this named collection. */
|
|
24486
|
+
collectionId: string().optional(),
|
|
24487
|
+
/** Frames that carry at least one saved annotation in one of these classes. */
|
|
24488
|
+
classes: array(RetrainMacroClassSchema).optional(),
|
|
24489
|
+
page: number().int().positive().default(1),
|
|
24490
|
+
pageSize: number().int().positive().max(100).default(50)
|
|
24491
|
+
});
|
|
24492
|
+
var RetrainCorpusPageSchema = object({
|
|
24493
|
+
frames: array(RetrainFrameSchema.extend({ workState: RetrainFrameWorkStateSchema })).readonly(),
|
|
24494
|
+
total: number().int().nonnegative(),
|
|
24495
|
+
page: number().int().positive(),
|
|
24496
|
+
pageSize: number().int().positive()
|
|
24497
|
+
});
|
|
24498
|
+
var RetrainCorpusKpiCameraRowSchema = object({
|
|
24499
|
+
deviceId: number(),
|
|
24500
|
+
unannotated: number().int().nonnegative(),
|
|
24501
|
+
annotated: number().int().nonnegative(),
|
|
24502
|
+
complete: number().int().nonnegative(),
|
|
24503
|
+
/** This camera's `complete` count divided by corpus `total`, in `[0,1]`.
|
|
24504
|
+
* `null` when the corpus is empty (no ratio). */
|
|
24505
|
+
pctOfCorpus: number().min(0).max(1).nullable()
|
|
24506
|
+
});
|
|
24507
|
+
var RetrainCorpusKpiSchema = object({
|
|
24508
|
+
total: number().int().nonnegative(),
|
|
24509
|
+
unannotated: number().int().nonnegative(),
|
|
24510
|
+
annotated: number().int().nonnegative(),
|
|
24511
|
+
complete: number().int().nonnegative(),
|
|
24512
|
+
cameras: array(RetrainCorpusKpiCameraRowSchema).readonly()
|
|
24513
|
+
});
|
|
24462
24514
|
/**
|
|
24463
24515
|
* Which frames an annotated export carries. Every field narrows; an empty
|
|
24464
|
-
* filter is every annotated copy.
|
|
24465
|
-
*
|
|
24466
|
-
*
|
|
24467
|
-
*
|
|
24516
|
+
* filter is every annotated copy. `frameIds` is the primitive a job or
|
|
24517
|
+
* download uses; `batchId` re-selects what an earlier export carried
|
|
24518
|
+
* (`exportedInBatch`). Frozen dataset versions were removed — live selection
|
|
24519
|
+
* resolves to `frameIds` at plan/start.
|
|
24468
24520
|
*/
|
|
24469
24521
|
var RetrainExportFilterSchema = object({
|
|
24470
24522
|
deviceIds: array(number()).optional(),
|
|
24471
24523
|
frameIds: array(string()).max(2e4).optional(),
|
|
24472
24524
|
/** Only frames in at least one of these named collections. */
|
|
24473
24525
|
collectionIds: array(string()).max(200).optional(),
|
|
24474
|
-
/**
|
|
24475
|
-
|
|
24476
|
-
datasetVersionId: string().optional(),
|
|
24526
|
+
/** Single collection (Frames filter bar). ANDed with `collectionIds` when both set. */
|
|
24527
|
+
collectionId: string().optional(),
|
|
24477
24528
|
batchId: string().optional(),
|
|
24478
24529
|
/** Only frames the operator marked complete (all subjects boxed). */
|
|
24479
|
-
completeOnly: boolean().optional()
|
|
24530
|
+
completeOnly: boolean().optional(),
|
|
24531
|
+
/** Exclusive work-state partition (`workStateOf`); same as the corpus list. */
|
|
24532
|
+
workState: RetrainFrameWorkStateSchema.optional(),
|
|
24533
|
+
/** Frames with at least one saved annotation in one of these classes. */
|
|
24534
|
+
classes: array(RetrainMacroClassSchema).optional()
|
|
24480
24535
|
});
|
|
24481
24536
|
/**
|
|
24482
24537
|
* `frames`: the full frame copies, boxes in `annotations.json`.
|
|
@@ -24676,8 +24731,7 @@ var RetrainDatasetStatsSchema = object({
|
|
|
24676
24731
|
completeFrames: number().int()
|
|
24677
24732
|
})).readonly()
|
|
24678
24733
|
});
|
|
24679
|
-
|
|
24680
|
-
var RetrainDatasetVersionSchema = object({
|
|
24734
|
+
object({
|
|
24681
24735
|
id: string(),
|
|
24682
24736
|
name: string(),
|
|
24683
24737
|
createdAt: number(),
|
|
@@ -24685,22 +24739,33 @@ var RetrainDatasetVersionSchema = object({
|
|
|
24685
24739
|
layout: RetrainExportLayoutSchema,
|
|
24686
24740
|
completeOnly: boolean(),
|
|
24687
24741
|
frameCount: number().int(),
|
|
24688
|
-
/** sha256 of what the frames taught when the version was frozen. */
|
|
24689
24742
|
annotationHash: string(),
|
|
24690
|
-
/** The export manifest schema the version was cut under. */
|
|
24691
24743
|
manifestSchema: string(),
|
|
24692
24744
|
stats: RetrainDatasetStatsSchema
|
|
24693
24745
|
});
|
|
24694
|
-
|
|
24695
|
-
|
|
24696
|
-
|
|
24746
|
+
/**
|
|
24747
|
+
* Live training corpus criteria — same shape as `TrainingCorpusSelection` on
|
|
24748
|
+
* the training cap. Resolved here so plan/start and the annotated export share
|
|
24749
|
+
* one definition of "the frames" (`buildRetrainExportPlan`).
|
|
24750
|
+
*/
|
|
24751
|
+
var RetrainTrainingCorpusSelectionSchema = object({
|
|
24752
|
+
collectionIds: array(string()).min(1),
|
|
24753
|
+
workState: _enum([
|
|
24754
|
+
"complete",
|
|
24755
|
+
"annotated_or_complete",
|
|
24756
|
+
"any_annotated"
|
|
24757
|
+
]).default("complete")
|
|
24758
|
+
});
|
|
24759
|
+
var RetrainTrainingCorpusResolveResultSchema = discriminatedUnion("kind", [object({
|
|
24760
|
+
kind: literal("resolved"),
|
|
24761
|
+
frameIds: array(string()).max(2e4).readonly(),
|
|
24762
|
+
stats: RetrainDatasetStatsSchema,
|
|
24763
|
+
annotationHash: string(),
|
|
24764
|
+
layout: RetrainExportLayoutSchema
|
|
24697
24765
|
}), object({
|
|
24698
24766
|
kind: literal("refused"),
|
|
24699
|
-
reason: _enum([
|
|
24700
|
-
|
|
24701
|
-
"duplicate-name",
|
|
24702
|
-
"no-frames"
|
|
24703
|
-
])
|
|
24767
|
+
reason: _enum(["unknown-collection", "no-frames"]),
|
|
24768
|
+
detail: string()
|
|
24704
24769
|
})]);
|
|
24705
24770
|
/** The outcome of a lifecycle move owned by the retrain page. */
|
|
24706
24771
|
var RetrainTransitionResultSchema = object({
|
|
@@ -25407,6 +25472,12 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
25407
25472
|
}), array(RetrainTrackSchema).readonly(), {
|
|
25408
25473
|
kind: "query",
|
|
25409
25474
|
auth: "admin"
|
|
25475
|
+
}), method(RetrainCorpusFilterSchema, RetrainCorpusPageSchema, {
|
|
25476
|
+
kind: "query",
|
|
25477
|
+
auth: "admin"
|
|
25478
|
+
}), method(object({}), RetrainCorpusKpiSchema, {
|
|
25479
|
+
kind: "query",
|
|
25480
|
+
auth: "admin"
|
|
25410
25481
|
}), method(object({ trackId: string() }), RetrainFrameListSchema, {
|
|
25411
25482
|
kind: "query",
|
|
25412
25483
|
auth: "admin"
|
|
@@ -25502,36 +25573,6 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
25502
25573
|
kind: "mutation",
|
|
25503
25574
|
auth: "admin",
|
|
25504
25575
|
timeoutMs: 12e4
|
|
25505
|
-
}), method(object({
|
|
25506
|
-
selection: RetrainDatasetSelectionSchema,
|
|
25507
|
-
completeOnly: boolean().optional()
|
|
25508
|
-
}), RetrainDatasetStatsSchema, {
|
|
25509
|
-
kind: "query",
|
|
25510
|
-
auth: "admin"
|
|
25511
|
-
}), method(object({
|
|
25512
|
-
name: string().max(120),
|
|
25513
|
-
selection: RetrainDatasetSelectionSchema,
|
|
25514
|
-
layout: RetrainExportLayoutSchema,
|
|
25515
|
-
completeOnly: boolean()
|
|
25516
|
-
}), CreateRetrainDatasetVersionResultSchema, {
|
|
25517
|
-
kind: "mutation",
|
|
25518
|
-
auth: "admin",
|
|
25519
|
-
timeoutMs: 12e4
|
|
25520
|
-
}), method(object({}), array(RetrainDatasetVersionSchema).readonly(), {
|
|
25521
|
-
kind: "query",
|
|
25522
|
-
auth: "admin"
|
|
25523
|
-
}), method(object({ id: string() }), object({ deleted: boolean() }), {
|
|
25524
|
-
kind: "mutation",
|
|
25525
|
-
auth: "admin"
|
|
25526
|
-
}), method(object({ id: string() }), object({
|
|
25527
|
-
found: boolean(),
|
|
25528
|
-
annotationHash: string(),
|
|
25529
|
-
matches: boolean(),
|
|
25530
|
-
missingFrames: number().int()
|
|
25531
|
-
}), {
|
|
25532
|
-
kind: "query",
|
|
25533
|
-
auth: "admin",
|
|
25534
|
-
timeoutMs: 12e4
|
|
25535
25576
|
}), method(object({}), array(RetrainAssistProfileSchema).readonly(), {
|
|
25536
25577
|
kind: "query",
|
|
25537
25578
|
auth: "admin"
|
|
@@ -25558,6 +25599,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
25558
25599
|
}), method(object({}), array(RetrainCollectionSchema).readonly(), {
|
|
25559
25600
|
kind: "query",
|
|
25560
25601
|
auth: "admin"
|
|
25602
|
+
}), method(RetrainTrainingCorpusSelectionSchema, RetrainTrainingCorpusResolveResultSchema, {
|
|
25603
|
+
kind: "query",
|
|
25604
|
+
auth: "admin",
|
|
25605
|
+
timeoutMs: 6e4
|
|
25561
25606
|
}), method(object({
|
|
25562
25607
|
id: string(),
|
|
25563
25608
|
name: string().max(120)
|
|
@@ -26174,11 +26219,14 @@ var HardwareClassIdSchema = _enum([
|
|
|
26174
26219
|
"intel-n-series",
|
|
26175
26220
|
"apple-m-base",
|
|
26176
26221
|
"apple-m-pro",
|
|
26222
|
+
"amd-phoenix",
|
|
26177
26223
|
"unknown"
|
|
26178
26224
|
]);
|
|
26179
26225
|
var AcceleratorKindSchema = _enum([
|
|
26180
26226
|
"intel-npu",
|
|
26181
26227
|
"intel-igpu",
|
|
26228
|
+
"amd-igpu",
|
|
26229
|
+
"amd-npu",
|
|
26182
26230
|
"x86-cpu",
|
|
26183
26231
|
"arm-cpu",
|
|
26184
26232
|
"apple-ane",
|
|
@@ -28108,6 +28156,8 @@ var AgentPipelineSettingsSchema = object({
|
|
|
28108
28156
|
* address is wrong (multi-homed host, NAT, custom interface).
|
|
28109
28157
|
*/
|
|
28110
28158
|
reachableHost: string().optional(),
|
|
28159
|
+
/** Hub-persisted UI colour (`--color-node-*` theme tokens). */
|
|
28160
|
+
color: NodeColorIdSchema.optional(),
|
|
28111
28161
|
/**
|
|
28112
28162
|
* Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
|
|
28113
28163
|
* weight, steps}. Absent / all-disabled ⇒ the node's single default
|
|
@@ -28657,8 +28707,9 @@ method(object({
|
|
|
28657
28707
|
auth: "admin"
|
|
28658
28708
|
}), method(object({
|
|
28659
28709
|
agentNodeId: string(),
|
|
28660
|
-
reachableHost: string().nullable()
|
|
28661
|
-
|
|
28710
|
+
reachableHost: string().nullable().optional(),
|
|
28711
|
+
color: NodeColorIdSchema.nullable().optional()
|
|
28712
|
+
}).refine((v) => v.reachableHost !== void 0 || v.color !== void 0, { message: "reachableHost or color required" }), object({ success: literal(true) }), {
|
|
28662
28713
|
kind: "mutation",
|
|
28663
28714
|
auth: "admin"
|
|
28664
28715
|
}), method(object({
|
|
@@ -36796,7 +36847,13 @@ var TopologyNodeSchema = object({
|
|
|
36796
36847
|
})).readonly(),
|
|
36797
36848
|
processes: array(TopologyProcessSchema).readonly(),
|
|
36798
36849
|
categories: array(TopologyCategorySchema).readonly(),
|
|
36799
|
-
rootPackage: TopologyRootPackageSchema.nullable()
|
|
36850
|
+
rootPackage: TopologyRootPackageSchema.nullable(),
|
|
36851
|
+
/**
|
|
36852
|
+
* How an online AGENT reaches the hub (mesh mTLS Release A): `tls` once it has
|
|
36853
|
+
* completed a mutual-TLS handshake, `clear` otherwise. Absent for the hub,
|
|
36854
|
+
* for offline rows and when the hub cannot tell.
|
|
36855
|
+
*/
|
|
36856
|
+
meshTransport: _enum(["tls", "clear"]).optional()
|
|
36800
36857
|
});
|
|
36801
36858
|
var CapUsageEdgeSchema = object({
|
|
36802
36859
|
callerAddonId: string(),
|
|
@@ -37766,7 +37823,15 @@ var GpuInfoSchema = object({
|
|
|
37766
37823
|
name: string(),
|
|
37767
37824
|
memoryMB: number().optional()
|
|
37768
37825
|
});
|
|
37769
|
-
var NpuInfoSchema = object({
|
|
37826
|
+
var NpuInfoSchema = object({
|
|
37827
|
+
type: _enum([
|
|
37828
|
+
"apple-ane",
|
|
37829
|
+
"intel-npu",
|
|
37830
|
+
"amd-xdna"
|
|
37831
|
+
]),
|
|
37832
|
+
name: string().optional(),
|
|
37833
|
+
generation: _enum(["xdna1", "xdna2"]).optional()
|
|
37834
|
+
});
|
|
37770
37835
|
var CoralInfoSchema = object({
|
|
37771
37836
|
type: literal("coral-edgetpu"),
|
|
37772
37837
|
bus: string().optional()
|
|
@@ -42509,9 +42574,11 @@ var zoneRulesCapability = {
|
|
|
42509
42574
|
* once is what makes a second provider (RunPod, a local NVIDIA node) a new
|
|
42510
42575
|
* manifest entry and nothing else.
|
|
42511
42576
|
*
|
|
42512
|
-
* Collection
|
|
42513
|
-
*
|
|
42514
|
-
*
|
|
42577
|
+
* Collection of provider **types** (addons). Each addon owns zero or more
|
|
42578
|
+
* **entries** (credentials + defaults). Concat-fans: `describe`,
|
|
42579
|
+
* `describeTypes`, `listEntries`, `listJobs`. Single-row work is keyed by
|
|
42580
|
+
* `entryId`; callers also pass the owning `addonId` as the collection
|
|
42581
|
+
* selector (broker posture). Every method is `admin`: these spend money.
|
|
42515
42582
|
*
|
|
42516
42583
|
* Every cloud object a provider creates is tagged with the orchestrator's
|
|
42517
42584
|
* `jobKey`, so a retried submit finds the job it already started instead of
|
|
@@ -42535,8 +42602,8 @@ var TrainingRegionOptionSchema = object({
|
|
|
42535
42602
|
priceMultiplier: number().positive()
|
|
42536
42603
|
});
|
|
42537
42604
|
/**
|
|
42538
|
-
* The provider's per-
|
|
42539
|
-
* live
|
|
42605
|
+
* The provider's per-entry settings, as the orchestrator reads them. They
|
|
42606
|
+
* live on the PROVIDER addon's entry (operator decision 2026-10-08: they
|
|
42540
42607
|
* depend on the user's account), never hard-coded in the orchestrator.
|
|
42541
42608
|
*/
|
|
42542
42609
|
var TrainingProviderDefaultsSchema = object({
|
|
@@ -42547,9 +42614,32 @@ var TrainingProviderDefaultsSchema = object({
|
|
|
42547
42614
|
/** Hours a FAILED job's cloud dataset is kept for debugging; 0 = delete at once. */
|
|
42548
42615
|
failedDatasetGraceHours: number().nonnegative()
|
|
42549
42616
|
});
|
|
42617
|
+
/** One creatable provider type, for the Add-entry dialog. */
|
|
42618
|
+
var TrainingProviderTypeSchema = object({
|
|
42619
|
+
typeId: string(),
|
|
42620
|
+
label: string(),
|
|
42621
|
+
/** Path under the addon package (e.g. `assets/training-modal/icon.svg`). */
|
|
42622
|
+
iconAsset: string(),
|
|
42623
|
+
/** Owning `training-provider` addon — collection selector for createEntry. */
|
|
42624
|
+
addonId: string()
|
|
42625
|
+
});
|
|
42626
|
+
/** One configured account / workspace under a provider type. */
|
|
42627
|
+
var TrainingProviderEntrySchema = object({
|
|
42628
|
+
entryId: string(),
|
|
42629
|
+
typeId: string(),
|
|
42630
|
+
name: string(),
|
|
42631
|
+
addonId: string(),
|
|
42632
|
+
/** Credentials are present — never the values. */
|
|
42633
|
+
configured: boolean()
|
|
42634
|
+
});
|
|
42550
42635
|
var TrainingProviderDescriptorSchema = object({
|
|
42551
42636
|
addonId: string(),
|
|
42552
|
-
|
|
42637
|
+
entryId: string(),
|
|
42638
|
+
typeId: string(),
|
|
42639
|
+
/** Operator-chosen entry name. */
|
|
42640
|
+
name: string(),
|
|
42641
|
+
iconAsset: string(),
|
|
42642
|
+
/** `modal`, `runpod`, `fake`, … — same as typeId for current providers. */
|
|
42553
42643
|
kind: string(),
|
|
42554
42644
|
label: string(),
|
|
42555
42645
|
gpuTypes: array(TrainingGpuOptionSchema).readonly(),
|
|
@@ -42613,20 +42703,30 @@ var TrainerSourceRefSchema = object({
|
|
|
42613
42703
|
/** A commit sha (never a branch) — the job must be reproducible. */
|
|
42614
42704
|
revision: string().regex(/^[0-9a-f]{7,64}$/)
|
|
42615
42705
|
});
|
|
42706
|
+
/** Cloud job identity — route with the owning addon's `addonId` selector. */
|
|
42616
42707
|
var JobRef = {
|
|
42617
|
-
|
|
42708
|
+
entryId: string().min(1),
|
|
42618
42709
|
jobKey: string().uuid()
|
|
42619
42710
|
};
|
|
42620
42711
|
var TrainingLogLineSchema = object({
|
|
42621
42712
|
ts: number(),
|
|
42622
42713
|
text: string()
|
|
42623
42714
|
});
|
|
42624
|
-
method(object({}), array(TrainingProviderDescriptorSchema).readonly(), { auth: "admin" }), method(object({
|
|
42715
|
+
method(object({}), array(TrainingProviderDescriptorSchema).readonly(), { auth: "admin" }), method(object({}), array(TrainingProviderTypeSchema).readonly(), { auth: "admin" }), method(object({}), array(TrainingProviderEntrySchema).readonly(), { auth: "admin" }), method(object({
|
|
42716
|
+
typeId: string().min(1),
|
|
42717
|
+
name: string().min(1)
|
|
42718
|
+
}), object({ entryId: string() }), {
|
|
42719
|
+
kind: "mutation",
|
|
42720
|
+
auth: "admin"
|
|
42721
|
+
}), method(object({ entryId: string().min(1) }), object({ ok: literal(true) }), {
|
|
42722
|
+
kind: "mutation",
|
|
42723
|
+
auth: "admin"
|
|
42724
|
+
}), method(object({ entryId: string().min(1) }), TrainingCredentialCheckSchema, {
|
|
42625
42725
|
kind: "mutation",
|
|
42626
42726
|
auth: "admin",
|
|
42627
42727
|
timeoutMs: 3e4
|
|
42628
42728
|
}), method(object({
|
|
42629
|
-
|
|
42729
|
+
entryId: string().min(1),
|
|
42630
42730
|
gpuType: string(),
|
|
42631
42731
|
region: string(),
|
|
42632
42732
|
datasetBytes: number().int().nonnegative(),
|
|
@@ -42692,7 +42792,7 @@ method(object({}), array(TrainingProviderDescriptorSchema).readonly(), { auth: "
|
|
|
42692
42792
|
kind: "mutation",
|
|
42693
42793
|
auth: "admin",
|
|
42694
42794
|
timeoutMs: 5 * 6e4
|
|
42695
|
-
}), method(object({
|
|
42795
|
+
}), method(object({ entryId: string().min(1).optional() }), array(ProviderJobStatusSchema).readonly(), {
|
|
42696
42796
|
auth: "admin",
|
|
42697
42797
|
timeoutMs: 2 * 6e4
|
|
42698
42798
|
});
|
|
@@ -42702,20 +42802,31 @@ method(object({}), array(TrainingProviderDescriptorSchema).readonly(), { auth: "
|
|
|
42702
42802
|
*
|
|
42703
42803
|
* It owns what every provider must agree on, written once:
|
|
42704
42804
|
*
|
|
42705
|
-
* - **Dataset versions.** Taken over from pipeline-analytics (D796): the rows
|
|
42706
|
-
* live here (D808); pipeline-analytics still CUTS a version (it owns the corpus and
|
|
42707
|
-
* the export plan) and reaches this store through the five row methods
|
|
42708
|
-
* below, so the Retrain page and the export did not change.
|
|
42709
42805
|
* - **Jobs.** A persisted state machine, a reconcile loop against the
|
|
42710
42806
|
* provider, a cost guard, a daily orphan sweep and the retention rules.
|
|
42711
42807
|
* - **The return flow.** Verified artefacts → Model Studio
|
|
42712
42808
|
* (`custom-model-registry.importModelBundle`) → canary on cameras →
|
|
42713
42809
|
* rollback. Nothing is ever registered automatically.
|
|
42714
42810
|
*
|
|
42811
|
+
* Plan/start takes a live {@link TrainingCorpusSelection} (collections +
|
|
42812
|
+
* work-state rule); frame ids are resolved via pipeline-analytics at that
|
|
42813
|
+
* moment and snapshotted on the job. No frozen dataset version.
|
|
42814
|
+
*
|
|
42715
42815
|
* Every method is `admin`.
|
|
42716
42816
|
*/
|
|
42717
|
-
/**
|
|
42718
|
-
|
|
42817
|
+
/**
|
|
42818
|
+
* Live corpus criteria for plan/start (design §5.2). Default is complete-only.
|
|
42819
|
+
* Frame ids are resolved at plan/start — never a frozen version id.
|
|
42820
|
+
*/
|
|
42821
|
+
var TrainingCorpusSelectionSchema = object({
|
|
42822
|
+
collectionIds: array(string()).min(1),
|
|
42823
|
+
/** Default complete-only for v1 */
|
|
42824
|
+
workState: _enum([
|
|
42825
|
+
"complete",
|
|
42826
|
+
"annotated_or_complete",
|
|
42827
|
+
"any_annotated"
|
|
42828
|
+
]).default("complete")
|
|
42829
|
+
});
|
|
42719
42830
|
/** A base model a detector job can fine-tune, and the baseline it is judged against. */
|
|
42720
42831
|
var TrainingBaseModelSchema = object({
|
|
42721
42832
|
modelId: string(),
|
|
@@ -42733,9 +42844,13 @@ var TrainingPresetSchema = _enum([
|
|
|
42733
42844
|
"thorough"
|
|
42734
42845
|
]);
|
|
42735
42846
|
var TrainingJobRequestSchema = object({
|
|
42736
|
-
|
|
42737
|
-
|
|
42738
|
-
|
|
42847
|
+
/** Live collection + work-state criteria; resolved at plan/start. */
|
|
42848
|
+
selection: TrainingCorpusSelectionSchema,
|
|
42849
|
+
/**
|
|
42850
|
+
* The provider **entry** that runs it (credentials + defaults).
|
|
42851
|
+
* Resolve to an owning addon via `training-provider.describe` / `listEntries`.
|
|
42852
|
+
*/
|
|
42853
|
+
entryId: string().min(1),
|
|
42739
42854
|
gpuType: string().min(1),
|
|
42740
42855
|
region: string(),
|
|
42741
42856
|
baseModelId: string().min(1),
|
|
@@ -42794,6 +42909,7 @@ var TrainingJobPlanSchema = object({
|
|
|
42794
42909
|
* result lives after the operator acted on it.
|
|
42795
42910
|
*/
|
|
42796
42911
|
var TrainingJobStateSchema = _enum([
|
|
42912
|
+
"queued",
|
|
42797
42913
|
"uploading",
|
|
42798
42914
|
"submitted",
|
|
42799
42915
|
"starting",
|
|
@@ -42847,6 +42963,11 @@ var TrainingJobSchema = object({
|
|
|
42847
42963
|
createdAt: number(),
|
|
42848
42964
|
updatedAt: number(),
|
|
42849
42965
|
state: TrainingJobStateSchema,
|
|
42966
|
+
/**
|
|
42967
|
+
* Shared by every job enqueued together via `startJobBatch`.
|
|
42968
|
+
* `null` for a lone `startJob`. The engine advances queued siblings by this id.
|
|
42969
|
+
*/
|
|
42970
|
+
batchId: string().nullable().default(null),
|
|
42850
42971
|
stage: TrainingStageSchema.nullable(),
|
|
42851
42972
|
failure: object({
|
|
42852
42973
|
reason: TrainingFailureReasonSchema,
|
|
@@ -42858,6 +42979,12 @@ var TrainingJobSchema = object({
|
|
|
42858
42979
|
maxRuntimeSec: number().int().positive(),
|
|
42859
42980
|
trainer: TrainerSourceRefSchema,
|
|
42860
42981
|
datasetLayout: RetrainExportLayoutSchema,
|
|
42982
|
+
/** Frame count snapshotted when the job started (audit; equals `frameIds.length`). */
|
|
42983
|
+
frameCount: number().int().nonnegative(),
|
|
42984
|
+
/** Resolved frame ids at start — the archive ships exactly these. */
|
|
42985
|
+
frameIds: array(string()).max(2e4).readonly(),
|
|
42986
|
+
/** Hash of what those frames taught at start (trainer `dataset.annotationHash`). */
|
|
42987
|
+
annotationHash: string(),
|
|
42861
42988
|
dataset: object({
|
|
42862
42989
|
bytes: number().int(),
|
|
42863
42990
|
sha256: string(),
|
|
@@ -42899,13 +43026,7 @@ var TrainingJobSchema = object({
|
|
|
42899
43026
|
canary: TrainingCanarySchema.nullable()
|
|
42900
43027
|
});
|
|
42901
43028
|
var IdInput = object({ id: string().min(1) });
|
|
42902
|
-
method(
|
|
42903
|
-
kind: "mutation",
|
|
42904
|
-
auth: "admin"
|
|
42905
|
-
}), method(IdInput, TrainingDatasetVersionRowSchema.nullable(), { auth: "admin" }), method(object({}), array(RetrainDatasetVersionSchema).readonly(), { auth: "admin" }), method(object({ name: string() }), object({ id: string().nullable() }), { auth: "admin" }), method(IdInput, object({ removed: boolean() }), {
|
|
42906
|
-
kind: "mutation",
|
|
42907
|
-
auth: "admin"
|
|
42908
|
-
}), method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" }), method(TrainingJobRequestSchema, TrainingJobPlanSchema, {
|
|
43029
|
+
method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" }), method(TrainingJobRequestSchema, TrainingJobPlanSchema, {
|
|
42909
43030
|
auth: "admin",
|
|
42910
43031
|
timeoutMs: 6e4
|
|
42911
43032
|
}), method(TrainingJobRequestSchema.extend({
|
|
@@ -42924,6 +43045,24 @@ method(TrainingDatasetVersionRowSchema, object({ stored: boolean() }), {
|
|
|
42924
43045
|
kind: "mutation",
|
|
42925
43046
|
auth: "admin",
|
|
42926
43047
|
timeoutMs: 12e4
|
|
43048
|
+
}), method(TrainingJobRequestSchema.omit({ baseModelId: true }).extend({
|
|
43049
|
+
baseModelIds: array(string().min(1)).min(1),
|
|
43050
|
+
name: string().min(1).max(120),
|
|
43051
|
+
maxCostUsd: number().positive(),
|
|
43052
|
+
maxRuntimeSec: number().int().positive(),
|
|
43053
|
+
idempotencyKey: string().min(8).max(80)
|
|
43054
|
+
}), discriminatedUnion("kind", [object({
|
|
43055
|
+
kind: literal("started"),
|
|
43056
|
+
batchId: string(),
|
|
43057
|
+
jobs: array(TrainingJobSchema).min(1).readonly()
|
|
43058
|
+
}), object({
|
|
43059
|
+
kind: literal("refused"),
|
|
43060
|
+
reason: TrainingRefusalReasonSchema,
|
|
43061
|
+
detail: string()
|
|
43062
|
+
})]), {
|
|
43063
|
+
kind: "mutation",
|
|
43064
|
+
auth: "admin",
|
|
43065
|
+
timeoutMs: 12e4
|
|
42927
43066
|
}), method(object({}), array(TrainingJobSchema).readonly(), { auth: "admin" }), method(IdInput, TrainingJobSchema.nullable(), { auth: "admin" }), method(IdInput, TrainingJobSchema, {
|
|
42928
43067
|
kind: "mutation",
|
|
42929
43068
|
auth: "admin",
|
|
@@ -48692,12 +48831,6 @@ Object.freeze({
|
|
|
48692
48831
|
addonId: null,
|
|
48693
48832
|
access: "create"
|
|
48694
48833
|
},
|
|
48695
|
-
"pipelineAnalytics.createRetrainDatasetVersion": {
|
|
48696
|
-
capName: "pipeline-analytics",
|
|
48697
|
-
capScope: "device",
|
|
48698
|
-
addonId: null,
|
|
48699
|
-
access: "create"
|
|
48700
|
-
},
|
|
48701
48834
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
48702
48835
|
capName: "pipeline-analytics",
|
|
48703
48836
|
capScope: "device",
|
|
@@ -48710,12 +48843,6 @@ Object.freeze({
|
|
|
48710
48843
|
addonId: null,
|
|
48711
48844
|
access: "delete"
|
|
48712
48845
|
},
|
|
48713
|
-
"pipelineAnalytics.deleteRetrainDatasetVersion": {
|
|
48714
|
-
capName: "pipeline-analytics",
|
|
48715
|
-
capScope: "device",
|
|
48716
|
-
addonId: null,
|
|
48717
|
-
access: "delete"
|
|
48718
|
-
},
|
|
48719
48846
|
"pipelineAnalytics.deleteTracks": {
|
|
48720
48847
|
capName: "pipeline-analytics",
|
|
48721
48848
|
capScope: "device",
|
|
@@ -48818,6 +48945,12 @@ Object.freeze({
|
|
|
48818
48945
|
addonId: null,
|
|
48819
48946
|
access: "view"
|
|
48820
48947
|
},
|
|
48948
|
+
"pipelineAnalytics.getRetrainCorpusKpi": {
|
|
48949
|
+
capName: "pipeline-analytics",
|
|
48950
|
+
capScope: "device",
|
|
48951
|
+
addonId: null,
|
|
48952
|
+
access: "view"
|
|
48953
|
+
},
|
|
48821
48954
|
"pipelineAnalytics.getRetrainExportUrl": {
|
|
48822
48955
|
capName: "pipeline-analytics",
|
|
48823
48956
|
capScope: "device",
|
|
@@ -48938,7 +49071,7 @@ Object.freeze({
|
|
|
48938
49071
|
addonId: null,
|
|
48939
49072
|
access: "view"
|
|
48940
49073
|
},
|
|
48941
|
-
"pipelineAnalytics.
|
|
49074
|
+
"pipelineAnalytics.listRetrainCorpusPage": {
|
|
48942
49075
|
capName: "pipeline-analytics",
|
|
48943
49076
|
capScope: "device",
|
|
48944
49077
|
addonId: null,
|
|
@@ -48992,12 +49125,6 @@ Object.freeze({
|
|
|
48992
49125
|
addonId: null,
|
|
48993
49126
|
access: "create"
|
|
48994
49127
|
},
|
|
48995
|
-
"pipelineAnalytics.previewRetrainDataset": {
|
|
48996
|
-
capName: "pipeline-analytics",
|
|
48997
|
-
capScope: "device",
|
|
48998
|
-
addonId: null,
|
|
48999
|
-
access: "view"
|
|
49000
|
-
},
|
|
49001
49128
|
"pipelineAnalytics.proposeRetrainAnnotations": {
|
|
49002
49129
|
capName: "pipeline-analytics",
|
|
49003
49130
|
capScope: "device",
|
|
@@ -49076,6 +49203,12 @@ Object.freeze({
|
|
|
49076
49203
|
addonId: null,
|
|
49077
49204
|
access: "create"
|
|
49078
49205
|
},
|
|
49206
|
+
"pipelineAnalytics.resolveRetrainTrainingCorpus": {
|
|
49207
|
+
capName: "pipeline-analytics",
|
|
49208
|
+
capScope: "device",
|
|
49209
|
+
addonId: null,
|
|
49210
|
+
access: "view"
|
|
49211
|
+
},
|
|
49079
49212
|
"pipelineAnalytics.restageRetrainTrack": {
|
|
49080
49213
|
capName: "pipeline-analytics",
|
|
49081
49214
|
capScope: "device",
|
|
@@ -49136,12 +49269,6 @@ Object.freeze({
|
|
|
49136
49269
|
addonId: null,
|
|
49137
49270
|
access: "create"
|
|
49138
49271
|
},
|
|
49139
|
-
"pipelineAnalytics.verifyRetrainDatasetVersion": {
|
|
49140
|
-
capName: "pipeline-analytics",
|
|
49141
|
-
capScope: "device",
|
|
49142
|
-
addonId: null,
|
|
49143
|
-
access: "view"
|
|
49144
|
-
},
|
|
49145
49272
|
"pipelineAnalytics.wipeAllAnalytics": {
|
|
49146
49273
|
capName: "pipeline-analytics",
|
|
49147
49274
|
capScope: "device",
|
|
@@ -51536,18 +51663,6 @@ Object.freeze({
|
|
|
51536
51663
|
addonId: null,
|
|
51537
51664
|
access: "create"
|
|
51538
51665
|
},
|
|
51539
|
-
"training.findDatasetVersionIdByName": {
|
|
51540
|
-
capName: "training",
|
|
51541
|
-
capScope: "system",
|
|
51542
|
-
addonId: null,
|
|
51543
|
-
access: "view"
|
|
51544
|
-
},
|
|
51545
|
-
"training.getDatasetVersion": {
|
|
51546
|
-
capName: "training",
|
|
51547
|
-
capScope: "system",
|
|
51548
|
-
addonId: null,
|
|
51549
|
-
access: "view"
|
|
51550
|
-
},
|
|
51551
51666
|
"training.getJob": {
|
|
51552
51667
|
capName: "training",
|
|
51553
51668
|
capScope: "system",
|
|
@@ -51566,12 +51681,6 @@ Object.freeze({
|
|
|
51566
51681
|
addonId: null,
|
|
51567
51682
|
access: "view"
|
|
51568
51683
|
},
|
|
51569
|
-
"training.listDatasetVersions": {
|
|
51570
|
-
capName: "training",
|
|
51571
|
-
capScope: "system",
|
|
51572
|
-
addonId: null,
|
|
51573
|
-
access: "view"
|
|
51574
|
-
},
|
|
51575
51684
|
"training.listJobs": {
|
|
51576
51685
|
capName: "training",
|
|
51577
51686
|
capScope: "system",
|
|
@@ -51584,54 +51693,66 @@ Object.freeze({
|
|
|
51584
51693
|
addonId: null,
|
|
51585
51694
|
access: "view"
|
|
51586
51695
|
},
|
|
51587
|
-
"training.
|
|
51696
|
+
"training.registerResult": {
|
|
51588
51697
|
capName: "training",
|
|
51589
51698
|
capScope: "system",
|
|
51590
51699
|
addonId: null,
|
|
51591
51700
|
access: "create"
|
|
51592
51701
|
},
|
|
51593
|
-
"training.
|
|
51702
|
+
"training.rollbackCanary": {
|
|
51594
51703
|
capName: "training",
|
|
51595
51704
|
capScope: "system",
|
|
51596
51705
|
addonId: null,
|
|
51597
51706
|
access: "create"
|
|
51598
51707
|
},
|
|
51599
|
-
"training.
|
|
51708
|
+
"training.startJob": {
|
|
51600
51709
|
capName: "training",
|
|
51601
51710
|
capScope: "system",
|
|
51602
51711
|
addonId: null,
|
|
51603
|
-
access: "
|
|
51712
|
+
access: "create"
|
|
51604
51713
|
},
|
|
51605
|
-
"training.
|
|
51714
|
+
"training.startJobBatch": {
|
|
51606
51715
|
capName: "training",
|
|
51607
51716
|
capScope: "system",
|
|
51608
51717
|
addonId: null,
|
|
51609
51718
|
access: "create"
|
|
51610
51719
|
},
|
|
51611
|
-
"
|
|
51612
|
-
capName: "training",
|
|
51720
|
+
"trainingProvider.cancelJob": {
|
|
51721
|
+
capName: "training-provider",
|
|
51613
51722
|
capScope: "system",
|
|
51614
51723
|
addonId: null,
|
|
51615
51724
|
access: "create"
|
|
51616
51725
|
},
|
|
51617
|
-
"trainingProvider.
|
|
51726
|
+
"trainingProvider.cleanupJob": {
|
|
51618
51727
|
capName: "training-provider",
|
|
51619
51728
|
capScope: "system",
|
|
51620
51729
|
addonId: null,
|
|
51621
51730
|
access: "create"
|
|
51622
51731
|
},
|
|
51623
|
-
"trainingProvider.
|
|
51732
|
+
"trainingProvider.createEntry": {
|
|
51624
51733
|
capName: "training-provider",
|
|
51625
51734
|
capScope: "system",
|
|
51626
51735
|
addonId: null,
|
|
51627
51736
|
access: "create"
|
|
51628
51737
|
},
|
|
51738
|
+
"trainingProvider.deleteEntry": {
|
|
51739
|
+
capName: "training-provider",
|
|
51740
|
+
capScope: "system",
|
|
51741
|
+
addonId: null,
|
|
51742
|
+
access: "delete"
|
|
51743
|
+
},
|
|
51629
51744
|
"trainingProvider.describe": {
|
|
51630
51745
|
capName: "training-provider",
|
|
51631
51746
|
capScope: "system",
|
|
51632
51747
|
addonId: null,
|
|
51633
51748
|
access: "view"
|
|
51634
51749
|
},
|
|
51750
|
+
"trainingProvider.describeTypes": {
|
|
51751
|
+
capName: "training-provider",
|
|
51752
|
+
capScope: "system",
|
|
51753
|
+
addonId: null,
|
|
51754
|
+
access: "view"
|
|
51755
|
+
},
|
|
51635
51756
|
"trainingProvider.estimateJob": {
|
|
51636
51757
|
capName: "training-provider",
|
|
51637
51758
|
capScope: "system",
|
|
@@ -51644,6 +51765,12 @@ Object.freeze({
|
|
|
51644
51765
|
addonId: null,
|
|
51645
51766
|
access: "view"
|
|
51646
51767
|
},
|
|
51768
|
+
"trainingProvider.listEntries": {
|
|
51769
|
+
capName: "training-provider",
|
|
51770
|
+
capScope: "system",
|
|
51771
|
+
addonId: null,
|
|
51772
|
+
access: "view"
|
|
51773
|
+
},
|
|
51647
51774
|
"trainingProvider.listJobEvents": {
|
|
51648
51775
|
capName: "training-provider",
|
|
51649
51776
|
capScope: "system",
|
|
@@ -55100,6 +55227,11 @@ Object.freeze({
|
|
|
55100
55227
|
form: "array",
|
|
55101
55228
|
optional: false
|
|
55102
55229
|
}],
|
|
55230
|
+
"pipelineAnalytics.listRetrainCorpusPage": [{
|
|
55231
|
+
name: "deviceIds",
|
|
55232
|
+
form: "array",
|
|
55233
|
+
optional: true
|
|
55234
|
+
}],
|
|
55103
55235
|
"pipelineAnalytics.listRetrainStaging": [{
|
|
55104
55236
|
name: "deviceIds",
|
|
55105
55237
|
form: "array",
|
|
@@ -56694,6 +56826,8 @@ var STATE_SUMMARY_VARS = [
|
|
|
56694
56826
|
[...RULE_TEXT],
|
|
56695
56827
|
[...RULE_TEXT],
|
|
56696
56828
|
[...RULE_TEXT],
|
|
56829
|
+
[...RULE_TEXT],
|
|
56830
|
+
[...RULE_TEXT],
|
|
56697
56831
|
([...RULE_TEXT], [...UPDATES]),
|
|
56698
56832
|
([...RULE_TEXT], [...PACKAGE_UPDATES]),
|
|
56699
56833
|
([...RULE_TEXT], [...PACKAGE_UPDATES]),
|
|
@@ -80252,6 +80386,19 @@ function sameConnection(a, b) {
|
|
|
80252
80386
|
return a.host === b.host && a.enableHmipRf === b.enableHmipRf && a.enableBidcosRf === b.enableBidcosRf && a.enableGroups === b.enableGroups && a.enableBidcosWired === b.enableBidcosWired && a.callbackHost === b.callbackHost && a.callbackPort === b.callbackPort && a.username === b.username && a.password === b.password && a.tls === b.tls;
|
|
80253
80387
|
}
|
|
80254
80388
|
/**
|
|
80389
|
+
* Delays (ms) between background restore retries after a failed
|
|
80390
|
+
* `facade.start()` (e.g. CCU `ECONNREFUSED`). Six attempts ≈ 2+5+10+20+30+60 s.
|
|
80391
|
+
* Exported for specs that drive the schedule with fake timers.
|
|
80392
|
+
*/
|
|
80393
|
+
var RESTORE_RETRY_DELAYS_MS = [
|
|
80394
|
+
2e3,
|
|
80395
|
+
5e3,
|
|
80396
|
+
1e4,
|
|
80397
|
+
2e4,
|
|
80398
|
+
3e4,
|
|
80399
|
+
6e4
|
|
80400
|
+
];
|
|
80401
|
+
/**
|
|
80255
80402
|
* Manages N live CCU connections ("brokers"), each backed by an
|
|
80256
80403
|
* {@link HmIntegrationManager}. Replaces the old single-CCU
|
|
80257
80404
|
* `homematic-gateway.ts` singleton.
|
|
@@ -80297,6 +80444,10 @@ var HmBrokerRegistry = class {
|
|
|
80297
80444
|
* typically in tests) facade creation is skipped.
|
|
80298
80445
|
*/
|
|
80299
80446
|
#useDefaultFactory;
|
|
80447
|
+
/** Pending restore-retry timers — cleared on {@link shutdown}. */
|
|
80448
|
+
#retryTimers = /* @__PURE__ */ new Map();
|
|
80449
|
+
/** True after {@link shutdown} — blocks further restore retries. */
|
|
80450
|
+
#shuttingDown = false;
|
|
80300
80451
|
constructor(logger, deps = {}) {
|
|
80301
80452
|
this.#logger = logger;
|
|
80302
80453
|
this.#onBrokerConnected = deps.onBrokerConnected ?? (() => void 0);
|
|
@@ -80321,10 +80472,13 @@ var HmBrokerRegistry = class {
|
|
|
80321
80472
|
* Restore previously-persisted broker entries on addon boot.
|
|
80322
80473
|
*
|
|
80323
80474
|
* Seeds the id counter from existing ids so future allocations never
|
|
80324
|
-
* collide. Starts each manager best-effort: a failed start is
|
|
80325
|
-
*
|
|
80475
|
+
* collide. Starts each manager best-effort: a failed start is rolled back
|
|
80476
|
+
* out of `#managers` (so a later attempt can rebuild) and scheduled for a
|
|
80477
|
+
* bounded background retry — a transient CCU `ECONNREFUSED` must not leave
|
|
80478
|
+
* the broker dead until an operator restarts the addon.
|
|
80326
80479
|
*/
|
|
80327
80480
|
async restore(entries) {
|
|
80481
|
+
this.#shuttingDown = false;
|
|
80328
80482
|
for (const entry of entries) this.#seedCounter(entry.id);
|
|
80329
80483
|
for (const entry of entries) try {
|
|
80330
80484
|
await this.#startManager(entry);
|
|
@@ -80334,6 +80488,7 @@ var HmBrokerRegistry = class {
|
|
|
80334
80488
|
tags: { brokerId: entry.id },
|
|
80335
80489
|
meta: { error: msg }
|
|
80336
80490
|
});
|
|
80491
|
+
this.#scheduleRestoreRetry(entry, 0);
|
|
80337
80492
|
}
|
|
80338
80493
|
}
|
|
80339
80494
|
/**
|
|
@@ -80341,6 +80496,9 @@ var HmBrokerRegistry = class {
|
|
|
80341
80496
|
* shutdown.
|
|
80342
80497
|
*/
|
|
80343
80498
|
async shutdown() {
|
|
80499
|
+
this.#shuttingDown = true;
|
|
80500
|
+
for (const timer of this.#retryTimers.values()) clearTimeout(timer);
|
|
80501
|
+
this.#retryTimers.clear();
|
|
80344
80502
|
const ids = Array.from(this.#managers.keys());
|
|
80345
80503
|
await Promise.all(ids.map(async (id) => {
|
|
80346
80504
|
const mgr = this.#managers.get(id);
|
|
@@ -80532,6 +80690,10 @@ var HmBrokerRegistry = class {
|
|
|
80532
80690
|
* Build (via the factory), register, and start the manager for one entry.
|
|
80533
80691
|
* If a manager for the same id already exists (e.g. a duplicate restore
|
|
80534
80692
|
* call), skip construction and only re-index the integration FK.
|
|
80693
|
+
*
|
|
80694
|
+
* On `start()` failure the half-built manager is abandoned so a retry can
|
|
80695
|
+
* construct a fresh one — leaving it in `#managers` used to make every
|
|
80696
|
+
* subsequent `#startManager` a no-op.
|
|
80535
80697
|
*/
|
|
80536
80698
|
async #startManager(entry) {
|
|
80537
80699
|
if (this.#managers.has(entry.id)) {
|
|
@@ -80548,13 +80710,92 @@ var HmBrokerRegistry = class {
|
|
|
80548
80710
|
});
|
|
80549
80711
|
this.#managers.set(entry.id, mgr);
|
|
80550
80712
|
if (entry.integrationId !== void 0) this.#integrationToBroker.set(entry.integrationId, entry.id);
|
|
80551
|
-
|
|
80713
|
+
try {
|
|
80714
|
+
await mgr.start();
|
|
80715
|
+
} catch (err) {
|
|
80716
|
+
await this.#abandonFailedStart(entry.id, mgr);
|
|
80717
|
+
throw err;
|
|
80718
|
+
}
|
|
80719
|
+
const pending = this.#retryTimers.get(entry.id);
|
|
80720
|
+
if (pending !== void 0) {
|
|
80721
|
+
clearTimeout(pending);
|
|
80722
|
+
this.#retryTimers.delete(entry.id);
|
|
80723
|
+
}
|
|
80552
80724
|
this.#logger.info("HmBrokerRegistry: manager started", {
|
|
80553
80725
|
tags: { brokerId: entry.id },
|
|
80554
80726
|
meta: { name: entry.name }
|
|
80555
80727
|
});
|
|
80556
80728
|
}
|
|
80557
80729
|
/**
|
|
80730
|
+
* Drop a manager that never reached `connected` so a later attempt can
|
|
80731
|
+
* rebuild it. Best-effort `stop()`; never throws.
|
|
80732
|
+
*/
|
|
80733
|
+
async #abandonFailedStart(id, mgr) {
|
|
80734
|
+
this.#managers.delete(id);
|
|
80735
|
+
this.#facades.delete(id);
|
|
80736
|
+
homematicFacades.set(id, null);
|
|
80737
|
+
try {
|
|
80738
|
+
await mgr.stop();
|
|
80739
|
+
} catch (err) {
|
|
80740
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
80741
|
+
this.#logger.debug("HmBrokerRegistry: abandon stop failed", {
|
|
80742
|
+
tags: { brokerId: id },
|
|
80743
|
+
meta: { error: msg }
|
|
80744
|
+
});
|
|
80745
|
+
}
|
|
80746
|
+
}
|
|
80747
|
+
/**
|
|
80748
|
+
* Schedule attempt `attemptIndex` of {@link RESTORE_RETRY_DELAYS_MS} for
|
|
80749
|
+
* `entry`. No-ops when the registry is shutting down or the schedule is
|
|
80750
|
+
* exhausted (warns once at the end).
|
|
80751
|
+
*/
|
|
80752
|
+
#scheduleRestoreRetry(entry, attemptIndex) {
|
|
80753
|
+
if (this.#shuttingDown) return;
|
|
80754
|
+
const delay = RESTORE_RETRY_DELAYS_MS[attemptIndex];
|
|
80755
|
+
if (delay === void 0) {
|
|
80756
|
+
this.#logger.warn("HmBrokerRegistry: restore retries exhausted", {
|
|
80757
|
+
tags: { brokerId: entry.id },
|
|
80758
|
+
meta: { attempts: RESTORE_RETRY_DELAYS_MS.length }
|
|
80759
|
+
});
|
|
80760
|
+
return;
|
|
80761
|
+
}
|
|
80762
|
+
const existing = this.#retryTimers.get(entry.id);
|
|
80763
|
+
if (existing !== void 0) clearTimeout(existing);
|
|
80764
|
+
const timer = setTimeout(() => {
|
|
80765
|
+
this.#retryTimers.delete(entry.id);
|
|
80766
|
+
this.#runRestoreRetry(entry, attemptIndex);
|
|
80767
|
+
}, delay);
|
|
80768
|
+
this.#retryTimers.set(entry.id, timer);
|
|
80769
|
+
this.#logger.info("HmBrokerRegistry: scheduling restore retry", {
|
|
80770
|
+
tags: { brokerId: entry.id },
|
|
80771
|
+
meta: {
|
|
80772
|
+
attempt: attemptIndex + 1,
|
|
80773
|
+
delayMs: delay
|
|
80774
|
+
}
|
|
80775
|
+
});
|
|
80776
|
+
}
|
|
80777
|
+
async #runRestoreRetry(entry, attemptIndex) {
|
|
80778
|
+
if (this.#shuttingDown) return;
|
|
80779
|
+
if (this.#managers.has(entry.id)) return;
|
|
80780
|
+
try {
|
|
80781
|
+
await this.#startManager(entry);
|
|
80782
|
+
this.#logger.info("HmBrokerRegistry: restore retry succeeded", {
|
|
80783
|
+
tags: { brokerId: entry.id },
|
|
80784
|
+
meta: { attempt: attemptIndex + 1 }
|
|
80785
|
+
});
|
|
80786
|
+
} catch (err) {
|
|
80787
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
80788
|
+
this.#logger.warn("HmBrokerRegistry: restore retry failed", {
|
|
80789
|
+
tags: { brokerId: entry.id },
|
|
80790
|
+
meta: {
|
|
80791
|
+
attempt: attemptIndex + 1,
|
|
80792
|
+
error: msg
|
|
80793
|
+
}
|
|
80794
|
+
});
|
|
80795
|
+
this.#scheduleRestoreRetry(entry, attemptIndex + 1);
|
|
80796
|
+
}
|
|
80797
|
+
}
|
|
80798
|
+
/**
|
|
80558
80799
|
* Allocate the next monotonic id in the `hm_NNN` sequence and advance
|
|
80559
80800
|
* the counter.
|
|
80560
80801
|
*/
|
|
@@ -83011,6 +83252,19 @@ var HmContainerDevice = class HmContainerDevice extends BaseDevice {
|
|
|
83011
83252
|
}
|
|
83012
83253
|
}
|
|
83013
83254
|
/**
|
|
83255
|
+
* Stamp `feature-probe.lastProbedAt` only when the CCU device is on the
|
|
83256
|
+
* facade. An empty accessory-spec list + a stamped probe is how the kernel
|
|
83257
|
+
* orphan-prunes linked children (`device-cap-proxy` safety gate): a restore
|
|
83258
|
+
* that races a CCU `ECONNREFUSED` used to delete every accessory and fence
|
|
83259
|
+
* their identities for 5 minutes. Leaving `lastProbedAt === 0` until the
|
|
83260
|
+
* device is present keeps the gate closed; `reprobe()` on broker connect
|
|
83261
|
+
* completes the probe and spawns/reconciles children for real.
|
|
83262
|
+
*/
|
|
83263
|
+
async onProbe() {
|
|
83264
|
+
if (this.resolveHmDevice() === null) return;
|
|
83265
|
+
await super.onProbe();
|
|
83266
|
+
}
|
|
83267
|
+
/**
|
|
83014
83268
|
* Derive the accessory children LIVE from the facade descriptor. Each child
|
|
83015
83269
|
* is a {@link HmEntitySpec} (the shared per-entity decomposition) wrapped into
|
|
83016
83270
|
* an `AccessoryChildSpec`: the `stableIdSuffix` IS the spec `key`, the broker
|
|
@@ -83150,6 +83404,7 @@ var HomematicProviderAddon = class extends BaseDeviceProvider {
|
|
|
83150
83404
|
this.registry.setOnBrokerConnected((brokerId) => {
|
|
83151
83405
|
this.ctx.logger.info("Homematic: broker connected", { meta: { brokerId } });
|
|
83152
83406
|
this.setBrokerDevicesOnline(brokerId, true);
|
|
83407
|
+
this.reprobeBrokerContainers(brokerId);
|
|
83153
83408
|
});
|
|
83154
83409
|
this.registry.setOnBrokerDisconnected((brokerId) => {
|
|
83155
83410
|
this.setBrokerDevicesOnline(brokerId, false);
|
|
@@ -83544,6 +83799,28 @@ var HomematicProviderAddon = class extends BaseDeviceProvider {
|
|
|
83544
83799
|
count: n
|
|
83545
83800
|
} });
|
|
83546
83801
|
}
|
|
83802
|
+
/**
|
|
83803
|
+
* Reprobe every adopted {@link HmContainerDevice} for `brokerId` so the
|
|
83804
|
+
* kernel re-runs accessory reconcile against the live facade. Best-effort:
|
|
83805
|
+
* one container's failure must not block the rest (same discipline as HA's
|
|
83806
|
+
* post-connect reconcile).
|
|
83807
|
+
*/
|
|
83808
|
+
async reprobeBrokerContainers(brokerId) {
|
|
83809
|
+
const reg = this.ctx.kernel.deviceRegistry;
|
|
83810
|
+
if (!reg) return;
|
|
83811
|
+
const containers = reg.getAllForAddon(this.addonId).filter((d) => d instanceof HmContainerDevice && d.config.get("brokerId") === brokerId);
|
|
83812
|
+
for (const container of containers) try {
|
|
83813
|
+
await container.reprobe();
|
|
83814
|
+
} catch (err) {
|
|
83815
|
+
this.ctx.logger.warn("Homematic: container reprobe failed", {
|
|
83816
|
+
tags: { deviceId: container.id },
|
|
83817
|
+
meta: {
|
|
83818
|
+
brokerId,
|
|
83819
|
+
error: errMsg(err)
|
|
83820
|
+
}
|
|
83821
|
+
});
|
|
83822
|
+
}
|
|
83823
|
+
}
|
|
83547
83824
|
/** Return the live registry or throw if the addon is not initialised. */
|
|
83548
83825
|
requireRegistry() {
|
|
83549
83826
|
if (!this.registry) throw new Error("Homematic provider not initialised");
|