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