@camstack/addon-post-analysis 1.2.643 → 1.2.645
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 +16 -1
- package/README.md +20 -12
- package/dist/{clip-model-registry-lKeBMKlT.js → clip-model-registry-DErmRdKe.js} +789 -111
- package/dist/{clip-model-registry-DdgT3gdf.mjs → clip-model-registry-DQIEgzhL.mjs} +789 -111
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/_stub.js +2 -2
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-B6X8TAQP.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-B-y32yJj.mjs} +3 -3
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DDmbZknW.mjs +26 -0
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DgC84J8L.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-CDPfOUWf.mjs → hostInit-CbKLHTBn.mjs} +3 -3
- package/dist/pipeline-analytics/index.js +3 -1
- package/dist/pipeline-analytics/index.mjs +3 -1
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BIjXlrFH.mjs +0 -26
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js--XkysBjS.mjs +0 -26
|
@@ -30,7 +30,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
}) : target, mod));
|
|
31
31
|
//#endregion
|
|
32
32
|
let node_crypto = require("node:crypto");
|
|
33
|
-
//#region ../types/dist/event-category-
|
|
33
|
+
//#region ../types/dist/event-category-hdMR7CTW.mjs
|
|
34
34
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
35
35
|
EventCategory["SystemBoot"] = "system.boot";
|
|
36
36
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -795,6 +795,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
795
795
|
*/
|
|
796
796
|
EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
|
|
797
797
|
/**
|
|
798
|
+
* An action run started or ended. Emitted by the `actions` surface.
|
|
799
|
+
* Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
|
|
800
|
+
*/
|
|
801
|
+
EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
|
|
802
|
+
/**
|
|
798
803
|
* Progress update from a running model conversion job.
|
|
799
804
|
* Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
|
|
800
805
|
* Emitted by `addon-model-studio` on the converting node.
|
|
@@ -5671,7 +5676,7 @@ var ZodIssueCode = {
|
|
|
5671
5676
|
var ZodFirstPartyTypeKind;
|
|
5672
5677
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5673
5678
|
//#endregion
|
|
5674
|
-
//#region ../types/dist/sleep
|
|
5679
|
+
//#region ../types/dist/sleep-BHjNez61.mjs
|
|
5675
5680
|
/**
|
|
5676
5681
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5677
5682
|
* window to float samples (D455).
|
|
@@ -9019,6 +9024,8 @@ var CAP_ADVANCE_FIELDS = Object.freeze({ "doorbell": "lastPressedAt" });
|
|
|
9019
9024
|
/** Every capability name, so addon code can check a name without the schema graph. */
|
|
9020
9025
|
var CAP_NAMES = Object.freeze([
|
|
9021
9026
|
"accessories",
|
|
9027
|
+
"action-source",
|
|
9028
|
+
"actions",
|
|
9022
9029
|
"addon-pages",
|
|
9023
9030
|
"addon-pages-source",
|
|
9024
9031
|
"addon-routes",
|
|
@@ -10321,6 +10328,18 @@ Object.freeze({
|
|
|
10321
10328
|
"path": "foodLevel",
|
|
10322
10329
|
"valueType": "number"
|
|
10323
10330
|
},
|
|
10331
|
+
{
|
|
10332
|
+
"path": "bowlFood",
|
|
10333
|
+
"valueType": "number"
|
|
10334
|
+
},
|
|
10335
|
+
{
|
|
10336
|
+
"path": "eating",
|
|
10337
|
+
"valueType": "boolean"
|
|
10338
|
+
},
|
|
10339
|
+
{
|
|
10340
|
+
"path": "supportsMarkRefilled",
|
|
10341
|
+
"valueType": "boolean"
|
|
10342
|
+
},
|
|
10324
10343
|
{
|
|
10325
10344
|
"path": "food1",
|
|
10326
10345
|
"valueType": "number"
|
|
@@ -16942,7 +16961,23 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
|
|
|
16942
16961
|
kind: literal("schedule"),
|
|
16943
16962
|
cron: string().min(1).max(120)
|
|
16944
16963
|
}),
|
|
16945
|
-
object({ kind: literal("manual") })
|
|
16964
|
+
object({ kind: literal("manual") }),
|
|
16965
|
+
object({
|
|
16966
|
+
kind: literal("detection"),
|
|
16967
|
+
/** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
|
|
16968
|
+
* matches every raw class that maps to it; any other name matches
|
|
16969
|
+
* exactly. */
|
|
16970
|
+
classes: array(string().min(1)).min(1),
|
|
16971
|
+
deviceIds: array(number().int().nonnegative()).min(1),
|
|
16972
|
+
/** The track must have visited at least one of these zones. */
|
|
16973
|
+
zones: array(string().min(1)).min(1).optional(),
|
|
16974
|
+
/** Best-so-far confidence the track must reach. */
|
|
16975
|
+
minScore: number().min(0).max(1).optional()
|
|
16976
|
+
}),
|
|
16977
|
+
object({
|
|
16978
|
+
kind: literal("interval"),
|
|
16979
|
+
minutes: number().int().min(1).max(1440)
|
|
16980
|
+
})
|
|
16946
16981
|
]);
|
|
16947
16982
|
/**
|
|
16948
16983
|
* One action step.
|
|
@@ -16962,28 +16997,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
|
|
|
16962
16997
|
* is called. The runner still receives a number and is untouched; the
|
|
16963
16998
|
* resolution is the recipe's job, not the runner's.
|
|
16964
16999
|
*/
|
|
17000
|
+
var AutomationWaitStepSchema = object({
|
|
17001
|
+
kind: literal("wait"),
|
|
17002
|
+
seconds: number().min(0).max(300)
|
|
17003
|
+
});
|
|
17004
|
+
var AutomationCapStepSchema = object({
|
|
17005
|
+
kind: literal("cap"),
|
|
17006
|
+
/**
|
|
17007
|
+
* One device, several same-family devices (locks / climate family / …),
|
|
17008
|
+
* or `{ $var }` for the device that triggered the run. An array is
|
|
17009
|
+
* fan-out at codegen — each id gets the same cap.method call.
|
|
17010
|
+
*/
|
|
17011
|
+
deviceId: union([
|
|
17012
|
+
number().int(),
|
|
17013
|
+
array(number().int()).min(1),
|
|
17014
|
+
object({ $var: string().min(1) })
|
|
17015
|
+
]),
|
|
17016
|
+
cap: string().min(1),
|
|
17017
|
+
method: string().min(1),
|
|
17018
|
+
/** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
|
|
17019
|
+
* SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
|
|
17020
|
+
* the expression leaf. */
|
|
17021
|
+
args: record(string(), unknown()).optional()
|
|
17022
|
+
});
|
|
17023
|
+
/**
|
|
17024
|
+
* The steps an internal Action may contain: cap and wait, and nothing that can
|
|
17025
|
+
* call back into an Action — so an Action can never reach itself (no cycles).
|
|
17026
|
+
*/
|
|
17027
|
+
var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
|
|
16965
17028
|
var AutomationActionSchema = discriminatedUnion("kind", [
|
|
17029
|
+
AutomationWaitStepSchema,
|
|
17030
|
+
AutomationCapStepSchema,
|
|
16966
17031
|
object({
|
|
16967
|
-
kind: literal("
|
|
16968
|
-
|
|
16969
|
-
|
|
16970
|
-
|
|
16971
|
-
|
|
16972
|
-
|
|
16973
|
-
|
|
16974
|
-
|
|
16975
|
-
|
|
16976
|
-
*/
|
|
16977
|
-
deviceId: union([
|
|
16978
|
-
number().int(),
|
|
16979
|
-
array(number().int()).min(1),
|
|
16980
|
-
object({ $var: string().min(1) })
|
|
16981
|
-
]),
|
|
16982
|
-
cap: string().min(1),
|
|
16983
|
-
method: string().min(1),
|
|
16984
|
-
/** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
|
|
16985
|
-
* evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
|
|
16986
|
-
args: record(string(), unknown()).optional()
|
|
17032
|
+
kind: literal("action"),
|
|
17033
|
+
/** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
|
|
17034
|
+
actionId: string().min(1),
|
|
17035
|
+
/** Values for the action's declared variables; the others take their default. */
|
|
17036
|
+
variables: record(string(), union([
|
|
17037
|
+
string(),
|
|
17038
|
+
number(),
|
|
17039
|
+
boolean()
|
|
17040
|
+
])).optional()
|
|
16987
17041
|
}),
|
|
16988
17042
|
object({
|
|
16989
17043
|
kind: literal("code"),
|
|
@@ -16992,10 +17046,378 @@ var AutomationActionSchema = discriminatedUnion("kind", [
|
|
|
16992
17046
|
code: string().min(1).max(2e4)
|
|
16993
17047
|
})
|
|
16994
17048
|
]);
|
|
17049
|
+
/**
|
|
17050
|
+
* How a trigger that arrives while the automation is busy (or cooling down) is
|
|
17051
|
+
* handled. One of the automation's execution modes, never a property of its
|
|
17052
|
+
* actions. Absent means `single`.
|
|
17053
|
+
*
|
|
17054
|
+
* - `single` — drop the trigger while a run is in progress (traced + logged).
|
|
17055
|
+
* - `restart` — abort the run in progress (at its next step boundary), start fresh.
|
|
17056
|
+
* - `queued` — queue up to `max` triggers, drop the rest (traced).
|
|
17057
|
+
* - `parallel` — up to `max` runs at once, drop the rest (traced).
|
|
17058
|
+
* - `cooldown` — `single`, and no new run until `minutes` after the last run
|
|
17059
|
+
* STARTED; persisted across a restart. A manual trigger bypasses only this
|
|
17060
|
+
* wait, never the single/queued limits.
|
|
17061
|
+
*/
|
|
17062
|
+
var AutomationRunModeSchema = discriminatedUnion("mode", [
|
|
17063
|
+
object({ mode: literal("single") }),
|
|
17064
|
+
object({ mode: literal("restart") }),
|
|
17065
|
+
object({
|
|
17066
|
+
mode: literal("queued"),
|
|
17067
|
+
max: number().int().min(1).max(10)
|
|
17068
|
+
}),
|
|
17069
|
+
object({
|
|
17070
|
+
mode: literal("parallel"),
|
|
17071
|
+
max: number().int().min(1).max(10)
|
|
17072
|
+
}),
|
|
17073
|
+
object({
|
|
17074
|
+
mode: literal("cooldown"),
|
|
17075
|
+
minutes: number().int().min(1).max(1440)
|
|
17076
|
+
})
|
|
17077
|
+
]);
|
|
16995
17078
|
var AutomationRecipeSchema = object({
|
|
16996
17079
|
triggers: array(AutomationTriggerSchema),
|
|
16997
17080
|
conditions: AutomationConditionSchema.optional(),
|
|
16998
|
-
actions: array(AutomationActionSchema)
|
|
17081
|
+
actions: array(AutomationActionSchema),
|
|
17082
|
+
runMode: AutomationRunModeSchema.optional(),
|
|
17083
|
+
/** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
|
|
17084
|
+
keepTraces: number().int().min(1).max(100).optional()
|
|
17085
|
+
});
|
|
17086
|
+
/**
|
|
17087
|
+
* The class names a per-class COUNT can ever be keyed on — the macro ids, and
|
|
17088
|
+
* only those.
|
|
17089
|
+
*
|
|
17090
|
+
* `preserveOriginal: false` below is the whole reason this set exists: the
|
|
17091
|
+
* executor maps each raw COCO label onto its macro and DROPS everything else,
|
|
17092
|
+
* so a tracked detection's `className` is always one of {@link MACRO_LABELS}.
|
|
17093
|
+
* Any surface that indexes counts by class name — the ZoneAnalytics occupancy
|
|
17094
|
+
* snapshot's `byClass`, and therefore every occupancy rule — can match nothing
|
|
17095
|
+
* else. Derived from the catalog, never hand-listed, so a new macro joins it by
|
|
17096
|
+
* being declared once.
|
|
17097
|
+
*
|
|
17098
|
+
* Cost of not having it, 2026-08-12: the notification rule editor offered the
|
|
17099
|
+
* full taxonomy for an occupancy class (occupancy is the one condition that
|
|
17100
|
+
* does not go through the engine's macro-expanding `expandClassSelector`), two
|
|
17101
|
+
* live rules were authored on `car`, and both counters read 0 forever.
|
|
17102
|
+
*/
|
|
17103
|
+
var DETECTION_MACRO_CLASSES = new Set([
|
|
17104
|
+
{
|
|
17105
|
+
id: "person",
|
|
17106
|
+
name: "Person"
|
|
17107
|
+
},
|
|
17108
|
+
{
|
|
17109
|
+
id: "vehicle",
|
|
17110
|
+
name: "Vehicle"
|
|
17111
|
+
},
|
|
17112
|
+
{
|
|
17113
|
+
id: "animal",
|
|
17114
|
+
name: "Animal"
|
|
17115
|
+
},
|
|
17116
|
+
{
|
|
17117
|
+
id: "package",
|
|
17118
|
+
name: "Package"
|
|
17119
|
+
}
|
|
17120
|
+
].map((l) => l.id));
|
|
17121
|
+
/** True when `className` is a macro the detector can actually emit (and hence a
|
|
17122
|
+
* class a count can be keyed on) — see {@link DETECTION_MACRO_CLASSES}. */
|
|
17123
|
+
function isDetectionMacroClass(className) {
|
|
17124
|
+
return DETECTION_MACRO_CLASSES.has(className.trim().toLowerCase());
|
|
17125
|
+
}
|
|
17126
|
+
var COCO_TO_MACRO = {
|
|
17127
|
+
mapping: {
|
|
17128
|
+
person: "person",
|
|
17129
|
+
bicycle: "vehicle",
|
|
17130
|
+
car: "vehicle",
|
|
17131
|
+
motorcycle: "vehicle",
|
|
17132
|
+
airplane: "vehicle",
|
|
17133
|
+
bus: "vehicle",
|
|
17134
|
+
train: "vehicle",
|
|
17135
|
+
truck: "vehicle",
|
|
17136
|
+
boat: "vehicle",
|
|
17137
|
+
bird: "animal",
|
|
17138
|
+
cat: "animal",
|
|
17139
|
+
dog: "animal",
|
|
17140
|
+
horse: "animal",
|
|
17141
|
+
sheep: "animal",
|
|
17142
|
+
cow: "animal",
|
|
17143
|
+
elephant: "animal",
|
|
17144
|
+
bear: "animal",
|
|
17145
|
+
zebra: "animal",
|
|
17146
|
+
giraffe: "animal",
|
|
17147
|
+
suitcase: "package",
|
|
17148
|
+
backpack: "package",
|
|
17149
|
+
handbag: "package"
|
|
17150
|
+
},
|
|
17151
|
+
preserveOriginal: false
|
|
17152
|
+
};
|
|
17153
|
+
new Set(Object.values(COCO_TO_MACRO.mapping));
|
|
17154
|
+
/**
|
|
17155
|
+
* Run traces — what an automation (or, later, an Action run) DID, node by node,
|
|
17156
|
+
* so the editor can paint every block green or red with its reason.
|
|
17157
|
+
*
|
|
17158
|
+
* A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
|
|
17159
|
+
* every condition node (containers and leaves, including the ones a
|
|
17160
|
+
* short-circuit never reached), the run-mode verdict and every action step —
|
|
17161
|
+
* each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
|
|
17162
|
+
* for an Action run). Skipped
|
|
17163
|
+
* evaluations are traced too, and identical consecutive skips collapse into a
|
|
17164
|
+
* repeat count so a trigger that fails every 5 minutes cannot flush real runs.
|
|
17165
|
+
*
|
|
17166
|
+
* {@link AutomationStepTraceSchema} is deliberately free of automation
|
|
17167
|
+
* vocabulary so an Action run records the same step shape.
|
|
17168
|
+
*/
|
|
17169
|
+
/** A value a trace may show: JSON primitives and short lists, nothing deeper. */
|
|
17170
|
+
var TraceValueSchema = union([
|
|
17171
|
+
string(),
|
|
17172
|
+
number(),
|
|
17173
|
+
boolean(),
|
|
17174
|
+
_null(),
|
|
17175
|
+
array(union([string(), number()]))
|
|
17176
|
+
]);
|
|
17177
|
+
var AutomationRunOutcomeSchema = _enum([
|
|
17178
|
+
"ran",
|
|
17179
|
+
"skipped-trigger",
|
|
17180
|
+
"skipped-conditions",
|
|
17181
|
+
"skipped-cooldown",
|
|
17182
|
+
"skipped-overlap",
|
|
17183
|
+
"failed",
|
|
17184
|
+
"aborted"
|
|
17185
|
+
]);
|
|
17186
|
+
/** `not-evaluated` = a short-circuit never reached the node. */
|
|
17187
|
+
var TraceNodeOutcomeSchema = _enum([
|
|
17188
|
+
"pass",
|
|
17189
|
+
"fail",
|
|
17190
|
+
"not-evaluated"
|
|
17191
|
+
]);
|
|
17192
|
+
var AutomationTriggerTraceSchema = object({
|
|
17193
|
+
kind: string().min(1),
|
|
17194
|
+
outcome: _enum(["pass", "fail"]),
|
|
17195
|
+
/** Why an event was rejected ("class person not in [dog]") or what fired. */
|
|
17196
|
+
reason: string(),
|
|
17197
|
+
/** deviceId, className, trackId, score … — only what the trigger exposes. */
|
|
17198
|
+
vars: record(string(), TraceValueSchema)
|
|
17199
|
+
});
|
|
17200
|
+
var AutomationConditionTraceNodeSchema = object({
|
|
17201
|
+
/** `conditions` for the root, `conditions.<i>` for its i-th child, … */
|
|
17202
|
+
path: string().min(1),
|
|
17203
|
+
kind: _enum([
|
|
17204
|
+
"all",
|
|
17205
|
+
"any",
|
|
17206
|
+
"not",
|
|
17207
|
+
"condition",
|
|
17208
|
+
"expression"
|
|
17209
|
+
]),
|
|
17210
|
+
outcome: TraceNodeOutcomeSchema,
|
|
17211
|
+
reason: string(),
|
|
17212
|
+
deviceId: number().int().optional(),
|
|
17213
|
+
cap: string().optional(),
|
|
17214
|
+
fieldPath: string().optional(),
|
|
17215
|
+
operator: string().optional(),
|
|
17216
|
+
expected: TraceValueSchema.optional(),
|
|
17217
|
+
/** What the mirror held; `null` when it held nothing (unknown). */
|
|
17218
|
+
observed: TraceValueSchema.optional()
|
|
17219
|
+
});
|
|
17220
|
+
var AutomationRunVerdictSchema = object({
|
|
17221
|
+
mode: AutomationRunModeSchema,
|
|
17222
|
+
decision: _enum([
|
|
17223
|
+
"run",
|
|
17224
|
+
"queued",
|
|
17225
|
+
"restart",
|
|
17226
|
+
"drop",
|
|
17227
|
+
"cooldown",
|
|
17228
|
+
"bypass"
|
|
17229
|
+
]),
|
|
17230
|
+
reason: string()
|
|
17231
|
+
});
|
|
17232
|
+
/** One executed (or not-run) step — shared by automations and Action runs. */
|
|
17233
|
+
var AutomationStepTraceSchema = object({
|
|
17234
|
+
/** `actions.<i>` */
|
|
17235
|
+
path: string().min(1),
|
|
17236
|
+
kind: string().min(1),
|
|
17237
|
+
cap: string().optional(),
|
|
17238
|
+
method: string().optional(),
|
|
17239
|
+
deviceId: number().int().optional(),
|
|
17240
|
+
startedAt: number().optional(),
|
|
17241
|
+
endedAt: number().optional(),
|
|
17242
|
+
outcome: _enum([
|
|
17243
|
+
"ok",
|
|
17244
|
+
"error",
|
|
17245
|
+
"not-run"
|
|
17246
|
+
]),
|
|
17247
|
+
message: string().optional()
|
|
17248
|
+
});
|
|
17249
|
+
var AutomationRunTraceSchema = object({
|
|
17250
|
+
runId: string().min(1),
|
|
17251
|
+
startedAt: number(),
|
|
17252
|
+
endedAt: number(),
|
|
17253
|
+
trigger: AutomationTriggerTraceSchema,
|
|
17254
|
+
conditions: array(AutomationConditionTraceNodeSchema),
|
|
17255
|
+
verdict: AutomationRunVerdictSchema.optional(),
|
|
17256
|
+
steps: array(AutomationStepTraceSchema),
|
|
17257
|
+
outcome: AutomationRunOutcomeSchema,
|
|
17258
|
+
/** How many identical consecutive skips this trace stands for (>= 1). */
|
|
17259
|
+
repeat: number().int().min(1),
|
|
17260
|
+
/** When the latest of those repeats happened. */
|
|
17261
|
+
lastAt: number()
|
|
17262
|
+
});
|
|
17263
|
+
/**
|
|
17264
|
+
* What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
|
|
17265
|
+
* `action:<actionId>`): the cooldown stamp and the trace ring.
|
|
17266
|
+
*/
|
|
17267
|
+
var AutomationStateDocSchema = object({
|
|
17268
|
+
version: literal(1),
|
|
17269
|
+
lastRunStartedAt: number().nullable(),
|
|
17270
|
+
traces: array(AutomationRunTraceSchema)
|
|
17271
|
+
});
|
|
17272
|
+
/**
|
|
17273
|
+
* Actions — named, runnable things an operator (or an automation) can start,
|
|
17274
|
+
* declared as LIST ENTRIES, never as devices.
|
|
17275
|
+
*
|
|
17276
|
+
* An entry is either **internal** (a short list of cap/wait steps kept in the
|
|
17277
|
+
* hub's `actions` record kind) or declared by an addon through the
|
|
17278
|
+
* `action-source` collection (a Home Assistant script, a scene …). The one
|
|
17279
|
+
* surface the UI and automations talk to is the `actions` cap; it keeps no
|
|
17280
|
+
* catalog of its own (D3) — every `list` asks the providers live.
|
|
17281
|
+
*
|
|
17282
|
+
* This file is the data half: the entry schema, the variables an entry may
|
|
17283
|
+
* declare, and the pure resolution of the values a run was given. It holds no
|
|
17284
|
+
* runtime.
|
|
17285
|
+
*/
|
|
17286
|
+
/** What a variable's value is. `select` takes one of `options`. */
|
|
17287
|
+
var ActionVariableTypeSchema = _enum([
|
|
17288
|
+
"string",
|
|
17289
|
+
"number",
|
|
17290
|
+
"boolean",
|
|
17291
|
+
"select"
|
|
17292
|
+
]);
|
|
17293
|
+
var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
17294
|
+
var ActionVariableValueSchema = union([
|
|
17295
|
+
string(),
|
|
17296
|
+
number(),
|
|
17297
|
+
boolean()
|
|
17298
|
+
]);
|
|
17299
|
+
/**
|
|
17300
|
+
* One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
|
|
17301
|
+
* value) or `{{vars.name}}` (inside a string) in their args.
|
|
17302
|
+
*/
|
|
17303
|
+
var ActionVariableSchema = object({
|
|
17304
|
+
name: string().regex(ACTION_VARIABLE_NAME_RE),
|
|
17305
|
+
label: string().min(1).max(120).optional(),
|
|
17306
|
+
type: ActionVariableTypeSchema,
|
|
17307
|
+
required: boolean().optional(),
|
|
17308
|
+
default: ActionVariableValueSchema.optional(),
|
|
17309
|
+
/** The allowed values of a `select`. */
|
|
17310
|
+
options: array(string().min(1)).min(1).optional()
|
|
17311
|
+
}).superRefine((v, ctx) => {
|
|
17312
|
+
if (v.type === "select" && v.options === void 0) ctx.addIssue({
|
|
17313
|
+
code: "custom",
|
|
17314
|
+
message: "a select variable needs options",
|
|
17315
|
+
path: ["options"]
|
|
17316
|
+
});
|
|
17317
|
+
if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
|
|
17318
|
+
code: "custom",
|
|
17319
|
+
message: variableValueError(v, v.default) ?? "invalid default",
|
|
17320
|
+
path: ["default"]
|
|
17321
|
+
});
|
|
17322
|
+
});
|
|
17323
|
+
/** Why `value` is not a legal value for the variable, or null when it is. */
|
|
17324
|
+
function variableValueError(variable, value) {
|
|
17325
|
+
switch (variable.type) {
|
|
17326
|
+
case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
|
|
17327
|
+
case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
|
|
17328
|
+
case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
|
|
17329
|
+
case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
|
|
17330
|
+
}
|
|
17331
|
+
}
|
|
17332
|
+
var ActionSourceKindSchema = _enum(["internal", "addon"]);
|
|
17333
|
+
function isInternalActionId(actionId) {
|
|
17334
|
+
return actionId.startsWith("internal:") && actionId.length > 9;
|
|
17335
|
+
}
|
|
17336
|
+
/** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
|
|
17337
|
+
function addonIdOfActionId(actionId) {
|
|
17338
|
+
if (isInternalActionId(actionId)) return null;
|
|
17339
|
+
const at = actionId.indexOf(":");
|
|
17340
|
+
return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
|
|
17341
|
+
}
|
|
17342
|
+
var ActionStatusSchema = object({
|
|
17343
|
+
isRunning: boolean(),
|
|
17344
|
+
/** Ms epoch the latest run STARTED; null when it never ran. */
|
|
17345
|
+
lastRunAt: number().nullable(),
|
|
17346
|
+
/** The latest run's failure; null on success or when it never ran. */
|
|
17347
|
+
lastError: string().nullable()
|
|
17348
|
+
});
|
|
17349
|
+
var ActionEntrySchema = object({
|
|
17350
|
+
/** `internal:<uuid>` or `<addonId>:<localId>`. */
|
|
17351
|
+
id: string().min(3),
|
|
17352
|
+
name: string().min(1).max(120),
|
|
17353
|
+
/** The addon that declared it; `core-blocks` for an internal one. */
|
|
17354
|
+
addonId: string().min(1),
|
|
17355
|
+
source: ActionSourceKindSchema,
|
|
17356
|
+
/** An addon-declared entry is edited where it was declared. */
|
|
17357
|
+
readOnly: boolean(),
|
|
17358
|
+
/** Internal only: cap and wait steps. No action-in-action, so no cycles. */
|
|
17359
|
+
steps: array(ActionStepSchema).min(1).max(50).optional(),
|
|
17360
|
+
variables: array(ActionVariableSchema).max(20).optional(),
|
|
17361
|
+
status: ActionStatusSchema
|
|
17362
|
+
}).superRefine((entry, ctx) => {
|
|
17363
|
+
if (entry.source === "internal") {
|
|
17364
|
+
if (!isInternalActionId(entry.id)) ctx.addIssue({
|
|
17365
|
+
code: "custom",
|
|
17366
|
+
message: "an internal action id is internal:<uuid>",
|
|
17367
|
+
path: ["id"]
|
|
17368
|
+
});
|
|
17369
|
+
return;
|
|
17370
|
+
}
|
|
17371
|
+
if (entry.steps !== void 0) ctx.addIssue({
|
|
17372
|
+
code: "custom",
|
|
17373
|
+
message: "only an internal action carries steps",
|
|
17374
|
+
path: ["steps"]
|
|
17375
|
+
});
|
|
17376
|
+
if (!entry.readOnly) ctx.addIssue({
|
|
17377
|
+
code: "custom",
|
|
17378
|
+
message: "an addon action is read-only here",
|
|
17379
|
+
path: ["readOnly"]
|
|
17380
|
+
});
|
|
17381
|
+
if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
|
|
17382
|
+
code: "custom",
|
|
17383
|
+
message: "an addon action id is <addonId>:<localId>",
|
|
17384
|
+
path: ["id"]
|
|
17385
|
+
});
|
|
17386
|
+
});
|
|
17387
|
+
/** What an operator writes for an internal action. */
|
|
17388
|
+
var ActionInputSchema = object({
|
|
17389
|
+
name: string().min(1).max(120),
|
|
17390
|
+
steps: array(ActionStepSchema).min(1).max(50),
|
|
17391
|
+
variables: array(ActionVariableSchema).max(20).optional()
|
|
17392
|
+
});
|
|
17393
|
+
/** Who started a run. Absent = the operator pressed it. */
|
|
17394
|
+
var ActionRunOriginSchema = object({
|
|
17395
|
+
/** The automation block whose step started it. */
|
|
17396
|
+
blockId: string().min(1).optional() });
|
|
17397
|
+
/** `started` = the caller did not ask to wait. */
|
|
17398
|
+
var ActionRunOutcomeSchema = union([AutomationRunOutcomeSchema, literal("started")]);
|
|
17399
|
+
var ActionRunResultSchema = object({
|
|
17400
|
+
runId: string().min(1),
|
|
17401
|
+
outcome: ActionRunOutcomeSchema,
|
|
17402
|
+
/** Why it did not run, or what failed. */
|
|
17403
|
+
message: string().optional()
|
|
17404
|
+
});
|
|
17405
|
+
_enum([
|
|
17406
|
+
"not-found",
|
|
17407
|
+
"read-only",
|
|
17408
|
+
"invalid-variables",
|
|
17409
|
+
"invalid-steps",
|
|
17410
|
+
"not-linked",
|
|
17411
|
+
"busy"
|
|
17412
|
+
]);
|
|
17413
|
+
object({
|
|
17414
|
+
actionId: string(),
|
|
17415
|
+
runId: string(),
|
|
17416
|
+
isRunning: boolean(),
|
|
17417
|
+
/** Set when the run ended. */
|
|
17418
|
+
outcome: AutomationRunOutcomeSchema.optional(),
|
|
17419
|
+
lastRunAt: number().nullable(),
|
|
17420
|
+
lastError: string().nullable()
|
|
16999
17421
|
});
|
|
17000
17422
|
/**
|
|
17001
17423
|
* `addon-pages` — system-scoped singleton aggregator cap. Public-facing
|
|
@@ -18609,7 +19031,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
18609
19031
|
*/
|
|
18610
19032
|
interactiveConnectPath: string().min(1).optional(),
|
|
18611
19033
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
18612
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
19034
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
19035
|
+
/**
|
|
19036
|
+
* The kind signs in through a server-held interactive session instead of
|
|
19037
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
19038
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
19039
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
19040
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
19041
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
19042
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
19043
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
19044
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
19045
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
19046
|
+
* offers it as the default path; the fields the session fills are
|
|
19047
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
19048
|
+
*/
|
|
19049
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
18613
19050
|
}))
|
|
18614
19051
|
});
|
|
18615
19052
|
var ListInputSchema = object({
|
|
@@ -20660,7 +21097,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
|
|
|
20660
21097
|
kind: "mutation",
|
|
20661
21098
|
auth: "admin",
|
|
20662
21099
|
access: "view"
|
|
20663
|
-
})
|
|
21100
|
+
}), method(object({
|
|
21101
|
+
blockId: string().min(1),
|
|
21102
|
+
trace: AutomationRunTraceSchema.optional(),
|
|
21103
|
+
runStartedAt: number().optional(),
|
|
21104
|
+
keepTraces: number().int().min(1).max(100).optional()
|
|
21105
|
+
}), _void(), {
|
|
21106
|
+
kind: "mutation",
|
|
21107
|
+
auth: "admin"
|
|
21108
|
+
}), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
|
|
21109
|
+
traces: array(AutomationRunTraceSchema),
|
|
21110
|
+
lastError: string().nullable()
|
|
21111
|
+
}), { auth: "admin" });
|
|
20664
21112
|
/**
|
|
20665
21113
|
* `custom-model-registry` — collection cap exposing operator-registered
|
|
20666
21114
|
* custom detection models. Each provider (today: `addon-model-studio`)
|
|
@@ -45668,7 +46116,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
45668
46116
|
});
|
|
45669
46117
|
/**
|
|
45670
46118
|
* Optional, richer endpoint shape returned by providers that expose
|
|
45671
|
-
* MORE than one ingress concurrently (Tailscale
|
|
46119
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
45672
46120
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
45673
46121
|
* the originating provider config (mode + sourcePort) so the
|
|
45674
46122
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -46061,73 +46509,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
|
|
|
46061
46509
|
kind: "mutation",
|
|
46062
46510
|
auth: "admin"
|
|
46063
46511
|
});
|
|
46064
|
-
/**
|
|
46065
|
-
* The class names a per-class COUNT can ever be keyed on — the macro ids, and
|
|
46066
|
-
* only those.
|
|
46067
|
-
*
|
|
46068
|
-
* `preserveOriginal: false` below is the whole reason this set exists: the
|
|
46069
|
-
* executor maps each raw COCO label onto its macro and DROPS everything else,
|
|
46070
|
-
* so a tracked detection's `className` is always one of {@link MACRO_LABELS}.
|
|
46071
|
-
* Any surface that indexes counts by class name — the ZoneAnalytics occupancy
|
|
46072
|
-
* snapshot's `byClass`, and therefore every occupancy rule — can match nothing
|
|
46073
|
-
* else. Derived from the catalog, never hand-listed, so a new macro joins it by
|
|
46074
|
-
* being declared once.
|
|
46075
|
-
*
|
|
46076
|
-
* Cost of not having it, 2026-08-12: the notification rule editor offered the
|
|
46077
|
-
* full taxonomy for an occupancy class (occupancy is the one condition that
|
|
46078
|
-
* does not go through the engine's macro-expanding `expandClassSelector`), two
|
|
46079
|
-
* live rules were authored on `car`, and both counters read 0 forever.
|
|
46080
|
-
*/
|
|
46081
|
-
var DETECTION_MACRO_CLASSES = new Set([
|
|
46082
|
-
{
|
|
46083
|
-
id: "person",
|
|
46084
|
-
name: "Person"
|
|
46085
|
-
},
|
|
46086
|
-
{
|
|
46087
|
-
id: "vehicle",
|
|
46088
|
-
name: "Vehicle"
|
|
46089
|
-
},
|
|
46090
|
-
{
|
|
46091
|
-
id: "animal",
|
|
46092
|
-
name: "Animal"
|
|
46093
|
-
},
|
|
46094
|
-
{
|
|
46095
|
-
id: "package",
|
|
46096
|
-
name: "Package"
|
|
46097
|
-
}
|
|
46098
|
-
].map((l) => l.id));
|
|
46099
|
-
/** True when `className` is a macro the detector can actually emit (and hence a
|
|
46100
|
-
* class a count can be keyed on) — see {@link DETECTION_MACRO_CLASSES}. */
|
|
46101
|
-
function isDetectionMacroClass(className) {
|
|
46102
|
-
return DETECTION_MACRO_CLASSES.has(className.trim().toLowerCase());
|
|
46103
|
-
}
|
|
46104
|
-
var COCO_TO_MACRO = {
|
|
46105
|
-
mapping: {
|
|
46106
|
-
person: "person",
|
|
46107
|
-
bicycle: "vehicle",
|
|
46108
|
-
car: "vehicle",
|
|
46109
|
-
motorcycle: "vehicle",
|
|
46110
|
-
airplane: "vehicle",
|
|
46111
|
-
bus: "vehicle",
|
|
46112
|
-
train: "vehicle",
|
|
46113
|
-
truck: "vehicle",
|
|
46114
|
-
boat: "vehicle",
|
|
46115
|
-
bird: "animal",
|
|
46116
|
-
cat: "animal",
|
|
46117
|
-
dog: "animal",
|
|
46118
|
-
horse: "animal",
|
|
46119
|
-
sheep: "animal",
|
|
46120
|
-
cow: "animal",
|
|
46121
|
-
elephant: "animal",
|
|
46122
|
-
bear: "animal",
|
|
46123
|
-
zebra: "animal",
|
|
46124
|
-
giraffe: "animal",
|
|
46125
|
-
suitcase: "package",
|
|
46126
|
-
backpack: "package",
|
|
46127
|
-
handbag: "package"
|
|
46128
|
-
},
|
|
46129
|
-
preserveOriginal: false
|
|
46130
|
-
};
|
|
46131
46512
|
var AUDIO_MACRO_LABELS = [
|
|
46132
46513
|
{
|
|
46133
46514
|
id: "speech",
|
|
@@ -60795,6 +61176,84 @@ var audioMetricsCapability = {
|
|
|
60795
61176
|
*/
|
|
60796
61177
|
history: "none"
|
|
60797
61178
|
};
|
|
61179
|
+
method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
|
|
61180
|
+
actionId: string().min(1),
|
|
61181
|
+
variables: record(string(), ActionVariableValueSchema).optional()
|
|
61182
|
+
}), _void(), {
|
|
61183
|
+
kind: "mutation",
|
|
61184
|
+
auth: "admin"
|
|
61185
|
+
}), method(object({ actionId: string().min(1) }), _void(), {
|
|
61186
|
+
kind: "mutation",
|
|
61187
|
+
auth: "admin"
|
|
61188
|
+
});
|
|
61189
|
+
/**
|
|
61190
|
+
* actions — the ONE surface for runnable actions, for the UI and for
|
|
61191
|
+
* automations. Provided by the core-blocks builtin on the hub.
|
|
61192
|
+
*
|
|
61193
|
+
* An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
|
|
61194
|
+
* steps, kept in the hub's `actions` record kind) or declared by an addon over
|
|
61195
|
+
* `action-source`. `list` asks every `action-source` provider LIVE and overlays
|
|
61196
|
+
* the run status from the hub's `runs` ledger; there is no catalog here to
|
|
61197
|
+
* drift (D3).
|
|
61198
|
+
*
|
|
61199
|
+
* **Permissions follow the camera, as linked devices do.** An action is linked
|
|
61200
|
+
* to cameras by the operator (`setLinks`, D356: nothing links itself). A
|
|
61201
|
+
* non-admin may `get` / `run` an action only through a camera they may see that
|
|
61202
|
+
* links it: they name the camera (`deviceId`, a top-level field so the scope
|
|
61203
|
+
* gate sees it) and the provider refuses an action that camera does not link.
|
|
61204
|
+
* An admin, and an in-process caller (an automation block), may run any action.
|
|
61205
|
+
* Every refusal is typed (`[not-linked] …`) and logged.
|
|
61206
|
+
*
|
|
61207
|
+
* A second `run` of an action that is already running is REFUSED — traced and
|
|
61208
|
+
* logged — never queued.
|
|
61209
|
+
*/
|
|
61210
|
+
var ActionIdInput = object({ actionId: string().min(1) });
|
|
61211
|
+
var ActionLinksSchema = object({
|
|
61212
|
+
deviceId: number().int().nonnegative(),
|
|
61213
|
+
actionIds: array(string().min(1)).max(100)
|
|
61214
|
+
});
|
|
61215
|
+
method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
|
|
61216
|
+
actionId: string().min(1),
|
|
61217
|
+
deviceId: number().int().nonnegative().optional()
|
|
61218
|
+
}), object({ action: ActionEntrySchema.nullable() }), {
|
|
61219
|
+
role: "viewer",
|
|
61220
|
+
auth: "protected",
|
|
61221
|
+
kind: "query",
|
|
61222
|
+
caller: "required"
|
|
61223
|
+
}), method(object({
|
|
61224
|
+
actionId: string().min(1),
|
|
61225
|
+
variables: record(string(), ActionVariableValueSchema).optional(),
|
|
61226
|
+
wait: boolean().optional(),
|
|
61227
|
+
origin: ActionRunOriginSchema.optional(),
|
|
61228
|
+
deviceId: number().int().nonnegative().optional()
|
|
61229
|
+
}), ActionRunResultSchema, {
|
|
61230
|
+
role: "viewer",
|
|
61231
|
+
auth: "protected",
|
|
61232
|
+
kind: "mutation",
|
|
61233
|
+
caller: "required"
|
|
61234
|
+
}), method(ActionIdInput, _void(), {
|
|
61235
|
+
kind: "mutation",
|
|
61236
|
+
auth: "admin"
|
|
61237
|
+
}), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
|
|
61238
|
+
kind: "mutation",
|
|
61239
|
+
auth: "admin"
|
|
61240
|
+
}), method(object({
|
|
61241
|
+
actionId: string().min(1),
|
|
61242
|
+
action: ActionInputSchema.partial()
|
|
61243
|
+
}), object({ action: ActionEntrySchema }), {
|
|
61244
|
+
kind: "mutation",
|
|
61245
|
+
auth: "admin"
|
|
61246
|
+
}), method(ActionIdInput, _void(), {
|
|
61247
|
+
kind: "mutation",
|
|
61248
|
+
auth: "admin"
|
|
61249
|
+
}), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
|
|
61250
|
+
role: "viewer",
|
|
61251
|
+
auth: "protected",
|
|
61252
|
+
kind: "query"
|
|
61253
|
+
}), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
|
|
61254
|
+
kind: "mutation",
|
|
61255
|
+
auth: "admin"
|
|
61256
|
+
});
|
|
60798
61257
|
/**
|
|
60799
61258
|
* Automation-control cap. Models HA `automation.*` entities on
|
|
60800
61259
|
* `DeviceType.Automation`. An automation is a trigger+condition+
|
|
@@ -60972,7 +61431,8 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
60972
61431
|
DeviceType.Switch,
|
|
60973
61432
|
DeviceType.PetFeeder,
|
|
60974
61433
|
DeviceType.Container,
|
|
60975
|
-
DeviceType.Thermostat
|
|
61434
|
+
DeviceType.Thermostat,
|
|
61435
|
+
DeviceType.EventEmitter
|
|
60976
61436
|
];
|
|
60977
61437
|
/** Generic Customize target for the percentage reading (D936). */
|
|
60978
61438
|
var batteryCustomize = {
|
|
@@ -67388,10 +67848,20 @@ var PetFeederDeviceStatusSchema = _enum([
|
|
|
67388
67848
|
]);
|
|
67389
67849
|
var gramsPortion = number().int().min(4).max(200);
|
|
67390
67850
|
var PetFeederStatusSchema = object({
|
|
67391
|
-
/** Food
|
|
67392
|
-
*
|
|
67393
|
-
* bowl
|
|
67851
|
+
/** Food in the TANK (hopper), as the feeder's own sensor reports it
|
|
67852
|
+
* (`state.food`). A coarse level code, not grams — `0` is empty. The
|
|
67853
|
+
* amount in the bowl is `bowlFood`. On dual-hopper models this is the
|
|
67854
|
+
* combined reading; per-hopper levels live in `food1`/`food2`. Null when
|
|
67855
|
+
* the device has not reported yet. */
|
|
67394
67856
|
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
67857
|
+
/** Food in the BOWL as the feeder reports it (`state.bowl`), in the
|
|
67858
|
+
* feeder's own units. Null when the model reports none. */
|
|
67859
|
+
bowlFood: number().nullable().meta(readingMeta("none")),
|
|
67860
|
+
/** True while the pet is eating (`state.eating`). */
|
|
67861
|
+
eating: boolean(),
|
|
67862
|
+
/** Whether `markFoodReplenished` does anything on this model. When false
|
|
67863
|
+
* the client must not offer it. */
|
|
67864
|
+
supportsMarkRefilled: boolean(),
|
|
67395
67865
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
67396
67866
|
* single-hopper models. */
|
|
67397
67867
|
food1: number().nullable().meta(readingMeta("none")),
|
|
@@ -67399,8 +67869,8 @@ var PetFeederStatusSchema = object({
|
|
|
67399
67869
|
* single-hopper models. */
|
|
67400
67870
|
food2: number().nullable().meta(readingMeta("none")),
|
|
67401
67871
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
67402
|
-
* (`device_class: problem`, on = low). True when the
|
|
67403
|
-
*
|
|
67872
|
+
* (`device_class: problem`, on = low). True when the tank reports empty,
|
|
67873
|
+
* or, on a dual-hopper model, when EITHER hopper is empty. */
|
|
67404
67874
|
lowFood: boolean(),
|
|
67405
67875
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
67406
67876
|
* device has no battery reading. */
|
|
@@ -67468,7 +67938,9 @@ var petFeederCapability = {
|
|
|
67468
67938
|
kind: "mutation",
|
|
67469
67939
|
auth: "protected"
|
|
67470
67940
|
}),
|
|
67471
|
-
/**
|
|
67941
|
+
/** Tell the PetKit cloud a hopper was refilled so it stops its low-food
|
|
67942
|
+
* reminders (D4H/D4S/D4SH only — see `supportsMarkRefilled`). It does not
|
|
67943
|
+
* change any sensor reading. */
|
|
67472
67944
|
markFoodReplenished: method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
67473
67945
|
kind: "mutation",
|
|
67474
67946
|
auth: "protected"
|
|
@@ -67541,6 +68013,7 @@ var petFeederCapability = {
|
|
|
67541
68013
|
*/
|
|
67542
68014
|
history: { fields: {
|
|
67543
68015
|
foodLevel: { kind: "gauge" },
|
|
68016
|
+
bowlFood: { kind: "gauge" },
|
|
67544
68017
|
food1: { kind: "gauge" },
|
|
67545
68018
|
food2: { kind: "gauge" },
|
|
67546
68019
|
batteryPower: {
|
|
@@ -67990,9 +68463,9 @@ var PowerMeterStatusSchema = object({
|
|
|
67990
68463
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
67991
68464
|
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
67992
68465
|
/** Voltage in volts. */
|
|
67993
|
-
volts: number().optional().meta(readingMeta("voltage")),
|
|
68466
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
67994
68467
|
/** Current in amperes. */
|
|
67995
|
-
amps: number().optional().meta(readingMeta("current")),
|
|
68468
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
67996
68469
|
/** Apparent power in volt-amperes. */
|
|
67997
68470
|
va: number().optional().meta(readingMeta("apparent-power")),
|
|
67998
68471
|
/** Power factor (0..1) if reported. */
|
|
@@ -68000,17 +68473,74 @@ var PowerMeterStatusSchema = object({
|
|
|
68000
68473
|
/** Ms epoch when the slice was last updated. */
|
|
68001
68474
|
lastFetchedAt: number()
|
|
68002
68475
|
});
|
|
68476
|
+
/**
|
|
68477
|
+
* Loads that draw metered mains power (D951). The reading is a feature of the
|
|
68478
|
+
* device itself — a plug, a lamp, a fan, an air conditioner, a boiler, a
|
|
68479
|
+
* vacuum dock — not a separate sensor beside it. A `Sensor` stays: a clamp
|
|
68480
|
+
* meter or a standalone energy monitor IS the device. Cover, lock, valve,
|
|
68481
|
+
* camera and the like are left out: their draw is not what anyone meters.
|
|
68482
|
+
*/
|
|
68483
|
+
var POWER_METER_DEVICE_TYPES = [
|
|
68484
|
+
DeviceType.Sensor,
|
|
68485
|
+
DeviceType.Switch,
|
|
68486
|
+
DeviceType.Light,
|
|
68487
|
+
DeviceType.Fan,
|
|
68488
|
+
DeviceType.Climate,
|
|
68489
|
+
DeviceType.Thermostat,
|
|
68490
|
+
DeviceType.Humidifier,
|
|
68491
|
+
DeviceType.WaterHeater,
|
|
68492
|
+
DeviceType.MediaPlayer,
|
|
68493
|
+
DeviceType.Washer,
|
|
68494
|
+
DeviceType.Dryer,
|
|
68495
|
+
DeviceType.Dishwasher,
|
|
68496
|
+
DeviceType.Vacuum,
|
|
68497
|
+
DeviceType.LawnMower,
|
|
68498
|
+
DeviceType.PetFeeder
|
|
68499
|
+
];
|
|
68500
|
+
/** Everything but a bare `Sensor`: a sensor that takes its reading from another sensor adds nothing. */
|
|
68501
|
+
var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== DeviceType.Sensor);
|
|
68502
|
+
/** One scalar target per reading; each is sourced from a device of its own (D951). */
|
|
68503
|
+
function powerTarget(id, unit) {
|
|
68504
|
+
return {
|
|
68505
|
+
id,
|
|
68506
|
+
cardinality: "scalar",
|
|
68507
|
+
vocabulary: {
|
|
68508
|
+
cap: "power-meter",
|
|
68509
|
+
stateField: id
|
|
68510
|
+
},
|
|
68511
|
+
deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
|
|
68512
|
+
apply: "add",
|
|
68513
|
+
path: id,
|
|
68514
|
+
sources: [{
|
|
68515
|
+
kind: "numeric",
|
|
68516
|
+
requiredUnit: unit,
|
|
68517
|
+
transforms: [{ kind: "identity" }]
|
|
68518
|
+
}],
|
|
68519
|
+
companions: [{
|
|
68520
|
+
kind: "clock",
|
|
68521
|
+
path: "lastFetchedAt",
|
|
68522
|
+
when: "always"
|
|
68523
|
+
}],
|
|
68524
|
+
sourceReport: { status: "assignment-status" },
|
|
68525
|
+
advancedExpression: true
|
|
68526
|
+
};
|
|
68527
|
+
}
|
|
68528
|
+
/** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
|
|
68529
|
+
var powerMeterCustomize = {
|
|
68530
|
+
version: 1,
|
|
68531
|
+
targets: [
|
|
68532
|
+
powerTarget("watts", "W"),
|
|
68533
|
+
powerTarget("kwhTotal", "kWh"),
|
|
68534
|
+
powerTarget("volts", "V"),
|
|
68535
|
+
powerTarget("amps", "A")
|
|
68536
|
+
]
|
|
68537
|
+
};
|
|
68003
68538
|
var powerMeterCapability = {
|
|
68004
68539
|
name: "power-meter",
|
|
68005
68540
|
scope: "device",
|
|
68006
68541
|
deviceNative: true,
|
|
68007
68542
|
mode: "singleton",
|
|
68008
|
-
deviceTypes:
|
|
68009
|
-
DeviceType.Sensor,
|
|
68010
|
-
DeviceType.Washer,
|
|
68011
|
-
DeviceType.Dryer,
|
|
68012
|
-
DeviceType.Dishwasher
|
|
68013
|
-
],
|
|
68543
|
+
deviceTypes: POWER_METER_DEVICE_TYPES,
|
|
68014
68544
|
methods: {},
|
|
68015
68545
|
status: {
|
|
68016
68546
|
schema: PowerMeterStatusSchema,
|
|
@@ -68067,7 +68597,8 @@ var powerMeterCapability = {
|
|
|
68067
68597
|
} },
|
|
68068
68598
|
/** Clock fields: written, but excluded from the compare that decides
|
|
68069
68599
|
* whether persisting is worth a SQLite commit. */
|
|
68070
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
68600
|
+
volatileStateFields: ["lastFetchedAt"],
|
|
68601
|
+
customize: powerMeterCustomize
|
|
68071
68602
|
};
|
|
68072
68603
|
/**
|
|
68073
68604
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -73505,7 +74036,7 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
73505
74036
|
});
|
|
73506
74037
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
73507
74038
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
73508
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
74039
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
73509
74040
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
73510
74041
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
73511
74042
|
new Set(CAP_NAMES);
|
|
@@ -74693,6 +75224,104 @@ Object.freeze({
|
|
|
74693
75224
|
access: "create",
|
|
74694
75225
|
role: "admin"
|
|
74695
75226
|
},
|
|
75227
|
+
"actions.create": {
|
|
75228
|
+
capName: "actions",
|
|
75229
|
+
capScope: "system",
|
|
75230
|
+
addonId: null,
|
|
75231
|
+
access: "create",
|
|
75232
|
+
role: "admin"
|
|
75233
|
+
},
|
|
75234
|
+
"actions.delete": {
|
|
75235
|
+
capName: "actions",
|
|
75236
|
+
capScope: "system",
|
|
75237
|
+
addonId: null,
|
|
75238
|
+
access: "delete",
|
|
75239
|
+
role: "admin"
|
|
75240
|
+
},
|
|
75241
|
+
"actions.get": {
|
|
75242
|
+
capName: "actions",
|
|
75243
|
+
capScope: "system",
|
|
75244
|
+
addonId: null,
|
|
75245
|
+
access: "view",
|
|
75246
|
+
role: "viewer"
|
|
75247
|
+
},
|
|
75248
|
+
"actions.getLinks": {
|
|
75249
|
+
capName: "actions",
|
|
75250
|
+
capScope: "system",
|
|
75251
|
+
addonId: null,
|
|
75252
|
+
access: "view",
|
|
75253
|
+
role: "admin"
|
|
75254
|
+
},
|
|
75255
|
+
"actions.getTraces": {
|
|
75256
|
+
capName: "actions",
|
|
75257
|
+
capScope: "system",
|
|
75258
|
+
addonId: null,
|
|
75259
|
+
access: "view",
|
|
75260
|
+
role: "admin"
|
|
75261
|
+
},
|
|
75262
|
+
"actions.list": {
|
|
75263
|
+
capName: "actions",
|
|
75264
|
+
capScope: "system",
|
|
75265
|
+
addonId: null,
|
|
75266
|
+
access: "view",
|
|
75267
|
+
role: "admin"
|
|
75268
|
+
},
|
|
75269
|
+
"actions.listForCamera": {
|
|
75270
|
+
capName: "actions",
|
|
75271
|
+
capScope: "system",
|
|
75272
|
+
addonId: null,
|
|
75273
|
+
access: "view",
|
|
75274
|
+
role: "viewer"
|
|
75275
|
+
},
|
|
75276
|
+
"actions.run": {
|
|
75277
|
+
capName: "actions",
|
|
75278
|
+
capScope: "system",
|
|
75279
|
+
addonId: null,
|
|
75280
|
+
access: "create",
|
|
75281
|
+
role: "viewer"
|
|
75282
|
+
},
|
|
75283
|
+
"actions.setLinks": {
|
|
75284
|
+
capName: "actions",
|
|
75285
|
+
capScope: "system",
|
|
75286
|
+
addonId: null,
|
|
75287
|
+
access: "create",
|
|
75288
|
+
role: "admin"
|
|
75289
|
+
},
|
|
75290
|
+
"actions.stop": {
|
|
75291
|
+
capName: "actions",
|
|
75292
|
+
capScope: "system",
|
|
75293
|
+
addonId: null,
|
|
75294
|
+
access: "create",
|
|
75295
|
+
role: "admin"
|
|
75296
|
+
},
|
|
75297
|
+
"actions.update": {
|
|
75298
|
+
capName: "actions",
|
|
75299
|
+
capScope: "system",
|
|
75300
|
+
addonId: null,
|
|
75301
|
+
access: "create",
|
|
75302
|
+
role: "admin"
|
|
75303
|
+
},
|
|
75304
|
+
"actionSource.listActions": {
|
|
75305
|
+
capName: "action-source",
|
|
75306
|
+
capScope: "system",
|
|
75307
|
+
addonId: null,
|
|
75308
|
+
access: "view",
|
|
75309
|
+
role: "admin"
|
|
75310
|
+
},
|
|
75311
|
+
"actionSource.runAction": {
|
|
75312
|
+
capName: "action-source",
|
|
75313
|
+
capScope: "system",
|
|
75314
|
+
addonId: null,
|
|
75315
|
+
access: "create",
|
|
75316
|
+
role: "admin"
|
|
75317
|
+
},
|
|
75318
|
+
"actionSource.stopAction": {
|
|
75319
|
+
capName: "action-source",
|
|
75320
|
+
capScope: "system",
|
|
75321
|
+
addonId: null,
|
|
75322
|
+
access: "create",
|
|
75323
|
+
role: "admin"
|
|
75324
|
+
},
|
|
74696
75325
|
"addonPages.listPages": {
|
|
74697
75326
|
capName: "addon-pages",
|
|
74698
75327
|
capScope: "system",
|
|
@@ -75974,6 +76603,13 @@ Object.freeze({
|
|
|
75974
76603
|
access: "view",
|
|
75975
76604
|
role: "admin"
|
|
75976
76605
|
},
|
|
76606
|
+
"coreBlocks.getAutomationRunState": {
|
|
76607
|
+
capName: "core-blocks",
|
|
76608
|
+
capScope: "system",
|
|
76609
|
+
addonId: null,
|
|
76610
|
+
access: "view",
|
|
76611
|
+
role: "admin"
|
|
76612
|
+
},
|
|
75977
76613
|
"coreBlocks.getBlockSettings": {
|
|
75978
76614
|
capName: "core-blocks",
|
|
75979
76615
|
capScope: "system",
|
|
@@ -75995,6 +76631,13 @@ Object.freeze({
|
|
|
75995
76631
|
access: "view",
|
|
75996
76632
|
role: "admin"
|
|
75997
76633
|
},
|
|
76634
|
+
"coreBlocks.getTraces": {
|
|
76635
|
+
capName: "core-blocks",
|
|
76636
|
+
capScope: "system",
|
|
76637
|
+
addonId: null,
|
|
76638
|
+
access: "view",
|
|
76639
|
+
role: "admin"
|
|
76640
|
+
},
|
|
75998
76641
|
"coreBlocks.getTypeDefs": {
|
|
75999
76642
|
capName: "core-blocks",
|
|
76000
76643
|
capScope: "system",
|
|
@@ -76030,6 +76673,13 @@ Object.freeze({
|
|
|
76030
76673
|
access: "create",
|
|
76031
76674
|
role: "admin"
|
|
76032
76675
|
},
|
|
76676
|
+
"coreBlocks.reportAutomationRun": {
|
|
76677
|
+
capName: "core-blocks",
|
|
76678
|
+
capScope: "system",
|
|
76679
|
+
addonId: null,
|
|
76680
|
+
access: "create",
|
|
76681
|
+
role: "admin"
|
|
76682
|
+
},
|
|
76033
76683
|
"coreBlocks.restart": {
|
|
76034
76684
|
capName: "core-blocks",
|
|
76035
76685
|
capScope: "system",
|
|
@@ -88184,6 +88834,8 @@ var ML = "model and training machinery — no device action";
|
|
|
88184
88834
|
var INTERNAL = "internal plumbing between addons — never operator-facing";
|
|
88185
88835
|
/** Every system-scoped cap, with why it is not a device's vocabulary. */
|
|
88186
88836
|
var SYSTEM_CAP_VOCABULARY = {
|
|
88837
|
+
"action-source": system(INTERNAL),
|
|
88838
|
+
actions: system("declared actions — run from the Actions page and from the cameras that link them"),
|
|
88187
88839
|
"addon-pages": system(UI_PLUMBING),
|
|
88188
88840
|
"addon-pages-source": system(UI_PLUMBING),
|
|
88189
88841
|
"addon-routes": system(UI_PLUMBING),
|
|
@@ -88380,6 +89032,31 @@ Object.freeze({
|
|
|
88380
89032
|
form: "single",
|
|
88381
89033
|
optional: false
|
|
88382
89034
|
}],
|
|
89035
|
+
"actions.get": [{
|
|
89036
|
+
name: "deviceId",
|
|
89037
|
+
form: "single",
|
|
89038
|
+
optional: true
|
|
89039
|
+
}],
|
|
89040
|
+
"actions.getLinks": [{
|
|
89041
|
+
name: "deviceId",
|
|
89042
|
+
form: "single",
|
|
89043
|
+
optional: false
|
|
89044
|
+
}],
|
|
89045
|
+
"actions.listForCamera": [{
|
|
89046
|
+
name: "deviceId",
|
|
89047
|
+
form: "single",
|
|
89048
|
+
optional: false
|
|
89049
|
+
}],
|
|
89050
|
+
"actions.run": [{
|
|
89051
|
+
name: "deviceId",
|
|
89052
|
+
form: "single",
|
|
89053
|
+
optional: true
|
|
89054
|
+
}],
|
|
89055
|
+
"actions.setLinks": [{
|
|
89056
|
+
name: "deviceId",
|
|
89057
|
+
form: "single",
|
|
89058
|
+
optional: false
|
|
89059
|
+
}],
|
|
88383
89060
|
"addonSettings.getDeviceSettings": [{
|
|
88384
89061
|
name: "deviceId",
|
|
88385
89062
|
form: "single",
|
|
@@ -95580,6 +96257,7 @@ function cosineSimilarity(a, b) {
|
|
|
95580
96257
|
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
95581
96258
|
return denom === 0 ? 0 : dotProduct / denom;
|
|
95582
96259
|
}
|
|
96260
|
+
String.raw`(?<=^|["'(\s>,\[{])`;
|
|
95583
96261
|
var MB = 1024 * 1024;
|
|
95584
96262
|
var DEFAULT_POOL_MEMORY_POLICY = {
|
|
95585
96263
|
sampleIntervalMs: 6e4,
|