@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
//#region ../types/dist/event-category-
|
|
2
|
+
//#region ../types/dist/event-category-hdMR7CTW.mjs
|
|
3
3
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4
4
|
EventCategory["SystemBoot"] = "system.boot";
|
|
5
5
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -764,6 +764,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
764
764
|
*/
|
|
765
765
|
EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
|
|
766
766
|
/**
|
|
767
|
+
* An action run started or ended. Emitted by the `actions` surface.
|
|
768
|
+
* Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
|
|
769
|
+
*/
|
|
770
|
+
EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
|
|
771
|
+
/**
|
|
767
772
|
* Progress update from a running model conversion job.
|
|
768
773
|
* Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
|
|
769
774
|
* Emitted by `addon-model-studio` on the converting node.
|
|
@@ -5640,7 +5645,7 @@ var ZodIssueCode = {
|
|
|
5640
5645
|
var ZodFirstPartyTypeKind;
|
|
5641
5646
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5642
5647
|
//#endregion
|
|
5643
|
-
//#region ../types/dist/sleep
|
|
5648
|
+
//#region ../types/dist/sleep-BHjNez61.mjs
|
|
5644
5649
|
/**
|
|
5645
5650
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5646
5651
|
* window to float samples (D455).
|
|
@@ -8988,6 +8993,8 @@ var CAP_ADVANCE_FIELDS = Object.freeze({ "doorbell": "lastPressedAt" });
|
|
|
8988
8993
|
/** Every capability name, so addon code can check a name without the schema graph. */
|
|
8989
8994
|
var CAP_NAMES = Object.freeze([
|
|
8990
8995
|
"accessories",
|
|
8996
|
+
"action-source",
|
|
8997
|
+
"actions",
|
|
8991
8998
|
"addon-pages",
|
|
8992
8999
|
"addon-pages-source",
|
|
8993
9000
|
"addon-routes",
|
|
@@ -10290,6 +10297,18 @@ Object.freeze({
|
|
|
10290
10297
|
"path": "foodLevel",
|
|
10291
10298
|
"valueType": "number"
|
|
10292
10299
|
},
|
|
10300
|
+
{
|
|
10301
|
+
"path": "bowlFood",
|
|
10302
|
+
"valueType": "number"
|
|
10303
|
+
},
|
|
10304
|
+
{
|
|
10305
|
+
"path": "eating",
|
|
10306
|
+
"valueType": "boolean"
|
|
10307
|
+
},
|
|
10308
|
+
{
|
|
10309
|
+
"path": "supportsMarkRefilled",
|
|
10310
|
+
"valueType": "boolean"
|
|
10311
|
+
},
|
|
10293
10312
|
{
|
|
10294
10313
|
"path": "food1",
|
|
10295
10314
|
"valueType": "number"
|
|
@@ -16911,7 +16930,23 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
|
|
|
16911
16930
|
kind: literal("schedule"),
|
|
16912
16931
|
cron: string().min(1).max(120)
|
|
16913
16932
|
}),
|
|
16914
|
-
object({ kind: literal("manual") })
|
|
16933
|
+
object({ kind: literal("manual") }),
|
|
16934
|
+
object({
|
|
16935
|
+
kind: literal("detection"),
|
|
16936
|
+
/** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
|
|
16937
|
+
* matches every raw class that maps to it; any other name matches
|
|
16938
|
+
* exactly. */
|
|
16939
|
+
classes: array(string().min(1)).min(1),
|
|
16940
|
+
deviceIds: array(number().int().nonnegative()).min(1),
|
|
16941
|
+
/** The track must have visited at least one of these zones. */
|
|
16942
|
+
zones: array(string().min(1)).min(1).optional(),
|
|
16943
|
+
/** Best-so-far confidence the track must reach. */
|
|
16944
|
+
minScore: number().min(0).max(1).optional()
|
|
16945
|
+
}),
|
|
16946
|
+
object({
|
|
16947
|
+
kind: literal("interval"),
|
|
16948
|
+
minutes: number().int().min(1).max(1440)
|
|
16949
|
+
})
|
|
16915
16950
|
]);
|
|
16916
16951
|
/**
|
|
16917
16952
|
* One action step.
|
|
@@ -16931,28 +16966,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
|
|
|
16931
16966
|
* is called. The runner still receives a number and is untouched; the
|
|
16932
16967
|
* resolution is the recipe's job, not the runner's.
|
|
16933
16968
|
*/
|
|
16969
|
+
var AutomationWaitStepSchema = object({
|
|
16970
|
+
kind: literal("wait"),
|
|
16971
|
+
seconds: number().min(0).max(300)
|
|
16972
|
+
});
|
|
16973
|
+
var AutomationCapStepSchema = object({
|
|
16974
|
+
kind: literal("cap"),
|
|
16975
|
+
/**
|
|
16976
|
+
* One device, several same-family devices (locks / climate family / …),
|
|
16977
|
+
* or `{ $var }` for the device that triggered the run. An array is
|
|
16978
|
+
* fan-out at codegen — each id gets the same cap.method call.
|
|
16979
|
+
*/
|
|
16980
|
+
deviceId: union([
|
|
16981
|
+
number().int(),
|
|
16982
|
+
array(number().int()).min(1),
|
|
16983
|
+
object({ $var: string().min(1) })
|
|
16984
|
+
]),
|
|
16985
|
+
cap: string().min(1),
|
|
16986
|
+
method: string().min(1),
|
|
16987
|
+
/** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
|
|
16988
|
+
* SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
|
|
16989
|
+
* the expression leaf. */
|
|
16990
|
+
args: record(string(), unknown()).optional()
|
|
16991
|
+
});
|
|
16992
|
+
/**
|
|
16993
|
+
* The steps an internal Action may contain: cap and wait, and nothing that can
|
|
16994
|
+
* call back into an Action — so an Action can never reach itself (no cycles).
|
|
16995
|
+
*/
|
|
16996
|
+
var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
|
|
16934
16997
|
var AutomationActionSchema = discriminatedUnion("kind", [
|
|
16998
|
+
AutomationWaitStepSchema,
|
|
16999
|
+
AutomationCapStepSchema,
|
|
16935
17000
|
object({
|
|
16936
|
-
kind: literal("
|
|
16937
|
-
|
|
16938
|
-
|
|
16939
|
-
|
|
16940
|
-
|
|
16941
|
-
|
|
16942
|
-
|
|
16943
|
-
|
|
16944
|
-
|
|
16945
|
-
*/
|
|
16946
|
-
deviceId: union([
|
|
16947
|
-
number().int(),
|
|
16948
|
-
array(number().int()).min(1),
|
|
16949
|
-
object({ $var: string().min(1) })
|
|
16950
|
-
]),
|
|
16951
|
-
cap: string().min(1),
|
|
16952
|
-
method: string().min(1),
|
|
16953
|
-
/** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
|
|
16954
|
-
* evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
|
|
16955
|
-
args: record(string(), unknown()).optional()
|
|
17001
|
+
kind: literal("action"),
|
|
17002
|
+
/** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
|
|
17003
|
+
actionId: string().min(1),
|
|
17004
|
+
/** Values for the action's declared variables; the others take their default. */
|
|
17005
|
+
variables: record(string(), union([
|
|
17006
|
+
string(),
|
|
17007
|
+
number(),
|
|
17008
|
+
boolean()
|
|
17009
|
+
])).optional()
|
|
16956
17010
|
}),
|
|
16957
17011
|
object({
|
|
16958
17012
|
kind: literal("code"),
|
|
@@ -16961,10 +17015,378 @@ var AutomationActionSchema = discriminatedUnion("kind", [
|
|
|
16961
17015
|
code: string().min(1).max(2e4)
|
|
16962
17016
|
})
|
|
16963
17017
|
]);
|
|
17018
|
+
/**
|
|
17019
|
+
* How a trigger that arrives while the automation is busy (or cooling down) is
|
|
17020
|
+
* handled. One of the automation's execution modes, never a property of its
|
|
17021
|
+
* actions. Absent means `single`.
|
|
17022
|
+
*
|
|
17023
|
+
* - `single` — drop the trigger while a run is in progress (traced + logged).
|
|
17024
|
+
* - `restart` — abort the run in progress (at its next step boundary), start fresh.
|
|
17025
|
+
* - `queued` — queue up to `max` triggers, drop the rest (traced).
|
|
17026
|
+
* - `parallel` — up to `max` runs at once, drop the rest (traced).
|
|
17027
|
+
* - `cooldown` — `single`, and no new run until `minutes` after the last run
|
|
17028
|
+
* STARTED; persisted across a restart. A manual trigger bypasses only this
|
|
17029
|
+
* wait, never the single/queued limits.
|
|
17030
|
+
*/
|
|
17031
|
+
var AutomationRunModeSchema = discriminatedUnion("mode", [
|
|
17032
|
+
object({ mode: literal("single") }),
|
|
17033
|
+
object({ mode: literal("restart") }),
|
|
17034
|
+
object({
|
|
17035
|
+
mode: literal("queued"),
|
|
17036
|
+
max: number().int().min(1).max(10)
|
|
17037
|
+
}),
|
|
17038
|
+
object({
|
|
17039
|
+
mode: literal("parallel"),
|
|
17040
|
+
max: number().int().min(1).max(10)
|
|
17041
|
+
}),
|
|
17042
|
+
object({
|
|
17043
|
+
mode: literal("cooldown"),
|
|
17044
|
+
minutes: number().int().min(1).max(1440)
|
|
17045
|
+
})
|
|
17046
|
+
]);
|
|
16964
17047
|
var AutomationRecipeSchema = object({
|
|
16965
17048
|
triggers: array(AutomationTriggerSchema),
|
|
16966
17049
|
conditions: AutomationConditionSchema.optional(),
|
|
16967
|
-
actions: array(AutomationActionSchema)
|
|
17050
|
+
actions: array(AutomationActionSchema),
|
|
17051
|
+
runMode: AutomationRunModeSchema.optional(),
|
|
17052
|
+
/** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
|
|
17053
|
+
keepTraces: number().int().min(1).max(100).optional()
|
|
17054
|
+
});
|
|
17055
|
+
/**
|
|
17056
|
+
* The class names a per-class COUNT can ever be keyed on — the macro ids, and
|
|
17057
|
+
* only those.
|
|
17058
|
+
*
|
|
17059
|
+
* `preserveOriginal: false` below is the whole reason this set exists: the
|
|
17060
|
+
* executor maps each raw COCO label onto its macro and DROPS everything else,
|
|
17061
|
+
* so a tracked detection's `className` is always one of {@link MACRO_LABELS}.
|
|
17062
|
+
* Any surface that indexes counts by class name — the ZoneAnalytics occupancy
|
|
17063
|
+
* snapshot's `byClass`, and therefore every occupancy rule — can match nothing
|
|
17064
|
+
* else. Derived from the catalog, never hand-listed, so a new macro joins it by
|
|
17065
|
+
* being declared once.
|
|
17066
|
+
*
|
|
17067
|
+
* Cost of not having it, 2026-08-12: the notification rule editor offered the
|
|
17068
|
+
* full taxonomy for an occupancy class (occupancy is the one condition that
|
|
17069
|
+
* does not go through the engine's macro-expanding `expandClassSelector`), two
|
|
17070
|
+
* live rules were authored on `car`, and both counters read 0 forever.
|
|
17071
|
+
*/
|
|
17072
|
+
var DETECTION_MACRO_CLASSES = new Set([
|
|
17073
|
+
{
|
|
17074
|
+
id: "person",
|
|
17075
|
+
name: "Person"
|
|
17076
|
+
},
|
|
17077
|
+
{
|
|
17078
|
+
id: "vehicle",
|
|
17079
|
+
name: "Vehicle"
|
|
17080
|
+
},
|
|
17081
|
+
{
|
|
17082
|
+
id: "animal",
|
|
17083
|
+
name: "Animal"
|
|
17084
|
+
},
|
|
17085
|
+
{
|
|
17086
|
+
id: "package",
|
|
17087
|
+
name: "Package"
|
|
17088
|
+
}
|
|
17089
|
+
].map((l) => l.id));
|
|
17090
|
+
/** True when `className` is a macro the detector can actually emit (and hence a
|
|
17091
|
+
* class a count can be keyed on) — see {@link DETECTION_MACRO_CLASSES}. */
|
|
17092
|
+
function isDetectionMacroClass(className) {
|
|
17093
|
+
return DETECTION_MACRO_CLASSES.has(className.trim().toLowerCase());
|
|
17094
|
+
}
|
|
17095
|
+
var COCO_TO_MACRO = {
|
|
17096
|
+
mapping: {
|
|
17097
|
+
person: "person",
|
|
17098
|
+
bicycle: "vehicle",
|
|
17099
|
+
car: "vehicle",
|
|
17100
|
+
motorcycle: "vehicle",
|
|
17101
|
+
airplane: "vehicle",
|
|
17102
|
+
bus: "vehicle",
|
|
17103
|
+
train: "vehicle",
|
|
17104
|
+
truck: "vehicle",
|
|
17105
|
+
boat: "vehicle",
|
|
17106
|
+
bird: "animal",
|
|
17107
|
+
cat: "animal",
|
|
17108
|
+
dog: "animal",
|
|
17109
|
+
horse: "animal",
|
|
17110
|
+
sheep: "animal",
|
|
17111
|
+
cow: "animal",
|
|
17112
|
+
elephant: "animal",
|
|
17113
|
+
bear: "animal",
|
|
17114
|
+
zebra: "animal",
|
|
17115
|
+
giraffe: "animal",
|
|
17116
|
+
suitcase: "package",
|
|
17117
|
+
backpack: "package",
|
|
17118
|
+
handbag: "package"
|
|
17119
|
+
},
|
|
17120
|
+
preserveOriginal: false
|
|
17121
|
+
};
|
|
17122
|
+
new Set(Object.values(COCO_TO_MACRO.mapping));
|
|
17123
|
+
/**
|
|
17124
|
+
* Run traces — what an automation (or, later, an Action run) DID, node by node,
|
|
17125
|
+
* so the editor can paint every block green or red with its reason.
|
|
17126
|
+
*
|
|
17127
|
+
* A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
|
|
17128
|
+
* every condition node (containers and leaves, including the ones a
|
|
17129
|
+
* short-circuit never reached), the run-mode verdict and every action step —
|
|
17130
|
+
* each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
|
|
17131
|
+
* for an Action run). Skipped
|
|
17132
|
+
* evaluations are traced too, and identical consecutive skips collapse into a
|
|
17133
|
+
* repeat count so a trigger that fails every 5 minutes cannot flush real runs.
|
|
17134
|
+
*
|
|
17135
|
+
* {@link AutomationStepTraceSchema} is deliberately free of automation
|
|
17136
|
+
* vocabulary so an Action run records the same step shape.
|
|
17137
|
+
*/
|
|
17138
|
+
/** A value a trace may show: JSON primitives and short lists, nothing deeper. */
|
|
17139
|
+
var TraceValueSchema = union([
|
|
17140
|
+
string(),
|
|
17141
|
+
number(),
|
|
17142
|
+
boolean(),
|
|
17143
|
+
_null(),
|
|
17144
|
+
array(union([string(), number()]))
|
|
17145
|
+
]);
|
|
17146
|
+
var AutomationRunOutcomeSchema = _enum([
|
|
17147
|
+
"ran",
|
|
17148
|
+
"skipped-trigger",
|
|
17149
|
+
"skipped-conditions",
|
|
17150
|
+
"skipped-cooldown",
|
|
17151
|
+
"skipped-overlap",
|
|
17152
|
+
"failed",
|
|
17153
|
+
"aborted"
|
|
17154
|
+
]);
|
|
17155
|
+
/** `not-evaluated` = a short-circuit never reached the node. */
|
|
17156
|
+
var TraceNodeOutcomeSchema = _enum([
|
|
17157
|
+
"pass",
|
|
17158
|
+
"fail",
|
|
17159
|
+
"not-evaluated"
|
|
17160
|
+
]);
|
|
17161
|
+
var AutomationTriggerTraceSchema = object({
|
|
17162
|
+
kind: string().min(1),
|
|
17163
|
+
outcome: _enum(["pass", "fail"]),
|
|
17164
|
+
/** Why an event was rejected ("class person not in [dog]") or what fired. */
|
|
17165
|
+
reason: string(),
|
|
17166
|
+
/** deviceId, className, trackId, score … — only what the trigger exposes. */
|
|
17167
|
+
vars: record(string(), TraceValueSchema)
|
|
17168
|
+
});
|
|
17169
|
+
var AutomationConditionTraceNodeSchema = object({
|
|
17170
|
+
/** `conditions` for the root, `conditions.<i>` for its i-th child, … */
|
|
17171
|
+
path: string().min(1),
|
|
17172
|
+
kind: _enum([
|
|
17173
|
+
"all",
|
|
17174
|
+
"any",
|
|
17175
|
+
"not",
|
|
17176
|
+
"condition",
|
|
17177
|
+
"expression"
|
|
17178
|
+
]),
|
|
17179
|
+
outcome: TraceNodeOutcomeSchema,
|
|
17180
|
+
reason: string(),
|
|
17181
|
+
deviceId: number().int().optional(),
|
|
17182
|
+
cap: string().optional(),
|
|
17183
|
+
fieldPath: string().optional(),
|
|
17184
|
+
operator: string().optional(),
|
|
17185
|
+
expected: TraceValueSchema.optional(),
|
|
17186
|
+
/** What the mirror held; `null` when it held nothing (unknown). */
|
|
17187
|
+
observed: TraceValueSchema.optional()
|
|
17188
|
+
});
|
|
17189
|
+
var AutomationRunVerdictSchema = object({
|
|
17190
|
+
mode: AutomationRunModeSchema,
|
|
17191
|
+
decision: _enum([
|
|
17192
|
+
"run",
|
|
17193
|
+
"queued",
|
|
17194
|
+
"restart",
|
|
17195
|
+
"drop",
|
|
17196
|
+
"cooldown",
|
|
17197
|
+
"bypass"
|
|
17198
|
+
]),
|
|
17199
|
+
reason: string()
|
|
17200
|
+
});
|
|
17201
|
+
/** One executed (or not-run) step — shared by automations and Action runs. */
|
|
17202
|
+
var AutomationStepTraceSchema = object({
|
|
17203
|
+
/** `actions.<i>` */
|
|
17204
|
+
path: string().min(1),
|
|
17205
|
+
kind: string().min(1),
|
|
17206
|
+
cap: string().optional(),
|
|
17207
|
+
method: string().optional(),
|
|
17208
|
+
deviceId: number().int().optional(),
|
|
17209
|
+
startedAt: number().optional(),
|
|
17210
|
+
endedAt: number().optional(),
|
|
17211
|
+
outcome: _enum([
|
|
17212
|
+
"ok",
|
|
17213
|
+
"error",
|
|
17214
|
+
"not-run"
|
|
17215
|
+
]),
|
|
17216
|
+
message: string().optional()
|
|
17217
|
+
});
|
|
17218
|
+
var AutomationRunTraceSchema = object({
|
|
17219
|
+
runId: string().min(1),
|
|
17220
|
+
startedAt: number(),
|
|
17221
|
+
endedAt: number(),
|
|
17222
|
+
trigger: AutomationTriggerTraceSchema,
|
|
17223
|
+
conditions: array(AutomationConditionTraceNodeSchema),
|
|
17224
|
+
verdict: AutomationRunVerdictSchema.optional(),
|
|
17225
|
+
steps: array(AutomationStepTraceSchema),
|
|
17226
|
+
outcome: AutomationRunOutcomeSchema,
|
|
17227
|
+
/** How many identical consecutive skips this trace stands for (>= 1). */
|
|
17228
|
+
repeat: number().int().min(1),
|
|
17229
|
+
/** When the latest of those repeats happened. */
|
|
17230
|
+
lastAt: number()
|
|
17231
|
+
});
|
|
17232
|
+
/**
|
|
17233
|
+
* What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
|
|
17234
|
+
* `action:<actionId>`): the cooldown stamp and the trace ring.
|
|
17235
|
+
*/
|
|
17236
|
+
var AutomationStateDocSchema = object({
|
|
17237
|
+
version: literal(1),
|
|
17238
|
+
lastRunStartedAt: number().nullable(),
|
|
17239
|
+
traces: array(AutomationRunTraceSchema)
|
|
17240
|
+
});
|
|
17241
|
+
/**
|
|
17242
|
+
* Actions — named, runnable things an operator (or an automation) can start,
|
|
17243
|
+
* declared as LIST ENTRIES, never as devices.
|
|
17244
|
+
*
|
|
17245
|
+
* An entry is either **internal** (a short list of cap/wait steps kept in the
|
|
17246
|
+
* hub's `actions` record kind) or declared by an addon through the
|
|
17247
|
+
* `action-source` collection (a Home Assistant script, a scene …). The one
|
|
17248
|
+
* surface the UI and automations talk to is the `actions` cap; it keeps no
|
|
17249
|
+
* catalog of its own (D3) — every `list` asks the providers live.
|
|
17250
|
+
*
|
|
17251
|
+
* This file is the data half: the entry schema, the variables an entry may
|
|
17252
|
+
* declare, and the pure resolution of the values a run was given. It holds no
|
|
17253
|
+
* runtime.
|
|
17254
|
+
*/
|
|
17255
|
+
/** What a variable's value is. `select` takes one of `options`. */
|
|
17256
|
+
var ActionVariableTypeSchema = _enum([
|
|
17257
|
+
"string",
|
|
17258
|
+
"number",
|
|
17259
|
+
"boolean",
|
|
17260
|
+
"select"
|
|
17261
|
+
]);
|
|
17262
|
+
var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
17263
|
+
var ActionVariableValueSchema = union([
|
|
17264
|
+
string(),
|
|
17265
|
+
number(),
|
|
17266
|
+
boolean()
|
|
17267
|
+
]);
|
|
17268
|
+
/**
|
|
17269
|
+
* One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
|
|
17270
|
+
* value) or `{{vars.name}}` (inside a string) in their args.
|
|
17271
|
+
*/
|
|
17272
|
+
var ActionVariableSchema = object({
|
|
17273
|
+
name: string().regex(ACTION_VARIABLE_NAME_RE),
|
|
17274
|
+
label: string().min(1).max(120).optional(),
|
|
17275
|
+
type: ActionVariableTypeSchema,
|
|
17276
|
+
required: boolean().optional(),
|
|
17277
|
+
default: ActionVariableValueSchema.optional(),
|
|
17278
|
+
/** The allowed values of a `select`. */
|
|
17279
|
+
options: array(string().min(1)).min(1).optional()
|
|
17280
|
+
}).superRefine((v, ctx) => {
|
|
17281
|
+
if (v.type === "select" && v.options === void 0) ctx.addIssue({
|
|
17282
|
+
code: "custom",
|
|
17283
|
+
message: "a select variable needs options",
|
|
17284
|
+
path: ["options"]
|
|
17285
|
+
});
|
|
17286
|
+
if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
|
|
17287
|
+
code: "custom",
|
|
17288
|
+
message: variableValueError(v, v.default) ?? "invalid default",
|
|
17289
|
+
path: ["default"]
|
|
17290
|
+
});
|
|
17291
|
+
});
|
|
17292
|
+
/** Why `value` is not a legal value for the variable, or null when it is. */
|
|
17293
|
+
function variableValueError(variable, value) {
|
|
17294
|
+
switch (variable.type) {
|
|
17295
|
+
case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
|
|
17296
|
+
case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
|
|
17297
|
+
case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
|
|
17298
|
+
case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
|
|
17299
|
+
}
|
|
17300
|
+
}
|
|
17301
|
+
var ActionSourceKindSchema = _enum(["internal", "addon"]);
|
|
17302
|
+
function isInternalActionId(actionId) {
|
|
17303
|
+
return actionId.startsWith("internal:") && actionId.length > 9;
|
|
17304
|
+
}
|
|
17305
|
+
/** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
|
|
17306
|
+
function addonIdOfActionId(actionId) {
|
|
17307
|
+
if (isInternalActionId(actionId)) return null;
|
|
17308
|
+
const at = actionId.indexOf(":");
|
|
17309
|
+
return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
|
|
17310
|
+
}
|
|
17311
|
+
var ActionStatusSchema = object({
|
|
17312
|
+
isRunning: boolean(),
|
|
17313
|
+
/** Ms epoch the latest run STARTED; null when it never ran. */
|
|
17314
|
+
lastRunAt: number().nullable(),
|
|
17315
|
+
/** The latest run's failure; null on success or when it never ran. */
|
|
17316
|
+
lastError: string().nullable()
|
|
17317
|
+
});
|
|
17318
|
+
var ActionEntrySchema = object({
|
|
17319
|
+
/** `internal:<uuid>` or `<addonId>:<localId>`. */
|
|
17320
|
+
id: string().min(3),
|
|
17321
|
+
name: string().min(1).max(120),
|
|
17322
|
+
/** The addon that declared it; `core-blocks` for an internal one. */
|
|
17323
|
+
addonId: string().min(1),
|
|
17324
|
+
source: ActionSourceKindSchema,
|
|
17325
|
+
/** An addon-declared entry is edited where it was declared. */
|
|
17326
|
+
readOnly: boolean(),
|
|
17327
|
+
/** Internal only: cap and wait steps. No action-in-action, so no cycles. */
|
|
17328
|
+
steps: array(ActionStepSchema).min(1).max(50).optional(),
|
|
17329
|
+
variables: array(ActionVariableSchema).max(20).optional(),
|
|
17330
|
+
status: ActionStatusSchema
|
|
17331
|
+
}).superRefine((entry, ctx) => {
|
|
17332
|
+
if (entry.source === "internal") {
|
|
17333
|
+
if (!isInternalActionId(entry.id)) ctx.addIssue({
|
|
17334
|
+
code: "custom",
|
|
17335
|
+
message: "an internal action id is internal:<uuid>",
|
|
17336
|
+
path: ["id"]
|
|
17337
|
+
});
|
|
17338
|
+
return;
|
|
17339
|
+
}
|
|
17340
|
+
if (entry.steps !== void 0) ctx.addIssue({
|
|
17341
|
+
code: "custom",
|
|
17342
|
+
message: "only an internal action carries steps",
|
|
17343
|
+
path: ["steps"]
|
|
17344
|
+
});
|
|
17345
|
+
if (!entry.readOnly) ctx.addIssue({
|
|
17346
|
+
code: "custom",
|
|
17347
|
+
message: "an addon action is read-only here",
|
|
17348
|
+
path: ["readOnly"]
|
|
17349
|
+
});
|
|
17350
|
+
if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
|
|
17351
|
+
code: "custom",
|
|
17352
|
+
message: "an addon action id is <addonId>:<localId>",
|
|
17353
|
+
path: ["id"]
|
|
17354
|
+
});
|
|
17355
|
+
});
|
|
17356
|
+
/** What an operator writes for an internal action. */
|
|
17357
|
+
var ActionInputSchema = object({
|
|
17358
|
+
name: string().min(1).max(120),
|
|
17359
|
+
steps: array(ActionStepSchema).min(1).max(50),
|
|
17360
|
+
variables: array(ActionVariableSchema).max(20).optional()
|
|
17361
|
+
});
|
|
17362
|
+
/** Who started a run. Absent = the operator pressed it. */
|
|
17363
|
+
var ActionRunOriginSchema = object({
|
|
17364
|
+
/** The automation block whose step started it. */
|
|
17365
|
+
blockId: string().min(1).optional() });
|
|
17366
|
+
/** `started` = the caller did not ask to wait. */
|
|
17367
|
+
var ActionRunOutcomeSchema = union([AutomationRunOutcomeSchema, literal("started")]);
|
|
17368
|
+
var ActionRunResultSchema = object({
|
|
17369
|
+
runId: string().min(1),
|
|
17370
|
+
outcome: ActionRunOutcomeSchema,
|
|
17371
|
+
/** Why it did not run, or what failed. */
|
|
17372
|
+
message: string().optional()
|
|
17373
|
+
});
|
|
17374
|
+
_enum([
|
|
17375
|
+
"not-found",
|
|
17376
|
+
"read-only",
|
|
17377
|
+
"invalid-variables",
|
|
17378
|
+
"invalid-steps",
|
|
17379
|
+
"not-linked",
|
|
17380
|
+
"busy"
|
|
17381
|
+
]);
|
|
17382
|
+
object({
|
|
17383
|
+
actionId: string(),
|
|
17384
|
+
runId: string(),
|
|
17385
|
+
isRunning: boolean(),
|
|
17386
|
+
/** Set when the run ended. */
|
|
17387
|
+
outcome: AutomationRunOutcomeSchema.optional(),
|
|
17388
|
+
lastRunAt: number().nullable(),
|
|
17389
|
+
lastError: string().nullable()
|
|
16968
17390
|
});
|
|
16969
17391
|
/**
|
|
16970
17392
|
* `addon-pages` — system-scoped singleton aggregator cap. Public-facing
|
|
@@ -18578,7 +19000,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
18578
19000
|
*/
|
|
18579
19001
|
interactiveConnectPath: string().min(1).optional(),
|
|
18580
19002
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
18581
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
19003
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
19004
|
+
/**
|
|
19005
|
+
* The kind signs in through a server-held interactive session instead of
|
|
19006
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
19007
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
19008
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
19009
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
19010
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
19011
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
19012
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
19013
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
19014
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
19015
|
+
* offers it as the default path; the fields the session fills are
|
|
19016
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
19017
|
+
*/
|
|
19018
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
18582
19019
|
}))
|
|
18583
19020
|
});
|
|
18584
19021
|
var ListInputSchema = object({
|
|
@@ -20629,7 +21066,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
|
|
|
20629
21066
|
kind: "mutation",
|
|
20630
21067
|
auth: "admin",
|
|
20631
21068
|
access: "view"
|
|
20632
|
-
})
|
|
21069
|
+
}), method(object({
|
|
21070
|
+
blockId: string().min(1),
|
|
21071
|
+
trace: AutomationRunTraceSchema.optional(),
|
|
21072
|
+
runStartedAt: number().optional(),
|
|
21073
|
+
keepTraces: number().int().min(1).max(100).optional()
|
|
21074
|
+
}), _void(), {
|
|
21075
|
+
kind: "mutation",
|
|
21076
|
+
auth: "admin"
|
|
21077
|
+
}), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
|
|
21078
|
+
traces: array(AutomationRunTraceSchema),
|
|
21079
|
+
lastError: string().nullable()
|
|
21080
|
+
}), { auth: "admin" });
|
|
20633
21081
|
/**
|
|
20634
21082
|
* `custom-model-registry` — collection cap exposing operator-registered
|
|
20635
21083
|
* custom detection models. Each provider (today: `addon-model-studio`)
|
|
@@ -45637,7 +46085,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
45637
46085
|
});
|
|
45638
46086
|
/**
|
|
45639
46087
|
* Optional, richer endpoint shape returned by providers that expose
|
|
45640
|
-
* MORE than one ingress concurrently (Tailscale
|
|
46088
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
45641
46089
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
45642
46090
|
* the originating provider config (mode + sourcePort) so the
|
|
45643
46091
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -46030,73 +46478,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
|
|
|
46030
46478
|
kind: "mutation",
|
|
46031
46479
|
auth: "admin"
|
|
46032
46480
|
});
|
|
46033
|
-
/**
|
|
46034
|
-
* The class names a per-class COUNT can ever be keyed on — the macro ids, and
|
|
46035
|
-
* only those.
|
|
46036
|
-
*
|
|
46037
|
-
* `preserveOriginal: false` below is the whole reason this set exists: the
|
|
46038
|
-
* executor maps each raw COCO label onto its macro and DROPS everything else,
|
|
46039
|
-
* so a tracked detection's `className` is always one of {@link MACRO_LABELS}.
|
|
46040
|
-
* Any surface that indexes counts by class name — the ZoneAnalytics occupancy
|
|
46041
|
-
* snapshot's `byClass`, and therefore every occupancy rule — can match nothing
|
|
46042
|
-
* else. Derived from the catalog, never hand-listed, so a new macro joins it by
|
|
46043
|
-
* being declared once.
|
|
46044
|
-
*
|
|
46045
|
-
* Cost of not having it, 2026-08-12: the notification rule editor offered the
|
|
46046
|
-
* full taxonomy for an occupancy class (occupancy is the one condition that
|
|
46047
|
-
* does not go through the engine's macro-expanding `expandClassSelector`), two
|
|
46048
|
-
* live rules were authored on `car`, and both counters read 0 forever.
|
|
46049
|
-
*/
|
|
46050
|
-
var DETECTION_MACRO_CLASSES = new Set([
|
|
46051
|
-
{
|
|
46052
|
-
id: "person",
|
|
46053
|
-
name: "Person"
|
|
46054
|
-
},
|
|
46055
|
-
{
|
|
46056
|
-
id: "vehicle",
|
|
46057
|
-
name: "Vehicle"
|
|
46058
|
-
},
|
|
46059
|
-
{
|
|
46060
|
-
id: "animal",
|
|
46061
|
-
name: "Animal"
|
|
46062
|
-
},
|
|
46063
|
-
{
|
|
46064
|
-
id: "package",
|
|
46065
|
-
name: "Package"
|
|
46066
|
-
}
|
|
46067
|
-
].map((l) => l.id));
|
|
46068
|
-
/** True when `className` is a macro the detector can actually emit (and hence a
|
|
46069
|
-
* class a count can be keyed on) — see {@link DETECTION_MACRO_CLASSES}. */
|
|
46070
|
-
function isDetectionMacroClass(className) {
|
|
46071
|
-
return DETECTION_MACRO_CLASSES.has(className.trim().toLowerCase());
|
|
46072
|
-
}
|
|
46073
|
-
var COCO_TO_MACRO = {
|
|
46074
|
-
mapping: {
|
|
46075
|
-
person: "person",
|
|
46076
|
-
bicycle: "vehicle",
|
|
46077
|
-
car: "vehicle",
|
|
46078
|
-
motorcycle: "vehicle",
|
|
46079
|
-
airplane: "vehicle",
|
|
46080
|
-
bus: "vehicle",
|
|
46081
|
-
train: "vehicle",
|
|
46082
|
-
truck: "vehicle",
|
|
46083
|
-
boat: "vehicle",
|
|
46084
|
-
bird: "animal",
|
|
46085
|
-
cat: "animal",
|
|
46086
|
-
dog: "animal",
|
|
46087
|
-
horse: "animal",
|
|
46088
|
-
sheep: "animal",
|
|
46089
|
-
cow: "animal",
|
|
46090
|
-
elephant: "animal",
|
|
46091
|
-
bear: "animal",
|
|
46092
|
-
zebra: "animal",
|
|
46093
|
-
giraffe: "animal",
|
|
46094
|
-
suitcase: "package",
|
|
46095
|
-
backpack: "package",
|
|
46096
|
-
handbag: "package"
|
|
46097
|
-
},
|
|
46098
|
-
preserveOriginal: false
|
|
46099
|
-
};
|
|
46100
46481
|
var AUDIO_MACRO_LABELS = [
|
|
46101
46482
|
{
|
|
46102
46483
|
id: "speech",
|
|
@@ -60764,6 +61145,84 @@ var audioMetricsCapability = {
|
|
|
60764
61145
|
*/
|
|
60765
61146
|
history: "none"
|
|
60766
61147
|
};
|
|
61148
|
+
method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
|
|
61149
|
+
actionId: string().min(1),
|
|
61150
|
+
variables: record(string(), ActionVariableValueSchema).optional()
|
|
61151
|
+
}), _void(), {
|
|
61152
|
+
kind: "mutation",
|
|
61153
|
+
auth: "admin"
|
|
61154
|
+
}), method(object({ actionId: string().min(1) }), _void(), {
|
|
61155
|
+
kind: "mutation",
|
|
61156
|
+
auth: "admin"
|
|
61157
|
+
});
|
|
61158
|
+
/**
|
|
61159
|
+
* actions — the ONE surface for runnable actions, for the UI and for
|
|
61160
|
+
* automations. Provided by the core-blocks builtin on the hub.
|
|
61161
|
+
*
|
|
61162
|
+
* An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
|
|
61163
|
+
* steps, kept in the hub's `actions` record kind) or declared by an addon over
|
|
61164
|
+
* `action-source`. `list` asks every `action-source` provider LIVE and overlays
|
|
61165
|
+
* the run status from the hub's `runs` ledger; there is no catalog here to
|
|
61166
|
+
* drift (D3).
|
|
61167
|
+
*
|
|
61168
|
+
* **Permissions follow the camera, as linked devices do.** An action is linked
|
|
61169
|
+
* to cameras by the operator (`setLinks`, D356: nothing links itself). A
|
|
61170
|
+
* non-admin may `get` / `run` an action only through a camera they may see that
|
|
61171
|
+
* links it: they name the camera (`deviceId`, a top-level field so the scope
|
|
61172
|
+
* gate sees it) and the provider refuses an action that camera does not link.
|
|
61173
|
+
* An admin, and an in-process caller (an automation block), may run any action.
|
|
61174
|
+
* Every refusal is typed (`[not-linked] …`) and logged.
|
|
61175
|
+
*
|
|
61176
|
+
* A second `run` of an action that is already running is REFUSED — traced and
|
|
61177
|
+
* logged — never queued.
|
|
61178
|
+
*/
|
|
61179
|
+
var ActionIdInput = object({ actionId: string().min(1) });
|
|
61180
|
+
var ActionLinksSchema = object({
|
|
61181
|
+
deviceId: number().int().nonnegative(),
|
|
61182
|
+
actionIds: array(string().min(1)).max(100)
|
|
61183
|
+
});
|
|
61184
|
+
method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
|
|
61185
|
+
actionId: string().min(1),
|
|
61186
|
+
deviceId: number().int().nonnegative().optional()
|
|
61187
|
+
}), object({ action: ActionEntrySchema.nullable() }), {
|
|
61188
|
+
role: "viewer",
|
|
61189
|
+
auth: "protected",
|
|
61190
|
+
kind: "query",
|
|
61191
|
+
caller: "required"
|
|
61192
|
+
}), method(object({
|
|
61193
|
+
actionId: string().min(1),
|
|
61194
|
+
variables: record(string(), ActionVariableValueSchema).optional(),
|
|
61195
|
+
wait: boolean().optional(),
|
|
61196
|
+
origin: ActionRunOriginSchema.optional(),
|
|
61197
|
+
deviceId: number().int().nonnegative().optional()
|
|
61198
|
+
}), ActionRunResultSchema, {
|
|
61199
|
+
role: "viewer",
|
|
61200
|
+
auth: "protected",
|
|
61201
|
+
kind: "mutation",
|
|
61202
|
+
caller: "required"
|
|
61203
|
+
}), method(ActionIdInput, _void(), {
|
|
61204
|
+
kind: "mutation",
|
|
61205
|
+
auth: "admin"
|
|
61206
|
+
}), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
|
|
61207
|
+
kind: "mutation",
|
|
61208
|
+
auth: "admin"
|
|
61209
|
+
}), method(object({
|
|
61210
|
+
actionId: string().min(1),
|
|
61211
|
+
action: ActionInputSchema.partial()
|
|
61212
|
+
}), object({ action: ActionEntrySchema }), {
|
|
61213
|
+
kind: "mutation",
|
|
61214
|
+
auth: "admin"
|
|
61215
|
+
}), method(ActionIdInput, _void(), {
|
|
61216
|
+
kind: "mutation",
|
|
61217
|
+
auth: "admin"
|
|
61218
|
+
}), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
|
|
61219
|
+
role: "viewer",
|
|
61220
|
+
auth: "protected",
|
|
61221
|
+
kind: "query"
|
|
61222
|
+
}), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
|
|
61223
|
+
kind: "mutation",
|
|
61224
|
+
auth: "admin"
|
|
61225
|
+
});
|
|
60767
61226
|
/**
|
|
60768
61227
|
* Automation-control cap. Models HA `automation.*` entities on
|
|
60769
61228
|
* `DeviceType.Automation`. An automation is a trigger+condition+
|
|
@@ -60941,7 +61400,8 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
60941
61400
|
DeviceType.Switch,
|
|
60942
61401
|
DeviceType.PetFeeder,
|
|
60943
61402
|
DeviceType.Container,
|
|
60944
|
-
DeviceType.Thermostat
|
|
61403
|
+
DeviceType.Thermostat,
|
|
61404
|
+
DeviceType.EventEmitter
|
|
60945
61405
|
];
|
|
60946
61406
|
/** Generic Customize target for the percentage reading (D936). */
|
|
60947
61407
|
var batteryCustomize = {
|
|
@@ -67357,10 +67817,20 @@ var PetFeederDeviceStatusSchema = _enum([
|
|
|
67357
67817
|
]);
|
|
67358
67818
|
var gramsPortion = number().int().min(4).max(200);
|
|
67359
67819
|
var PetFeederStatusSchema = object({
|
|
67360
|
-
/** Food
|
|
67361
|
-
*
|
|
67362
|
-
* bowl
|
|
67820
|
+
/** Food in the TANK (hopper), as the feeder's own sensor reports it
|
|
67821
|
+
* (`state.food`). A coarse level code, not grams — `0` is empty. The
|
|
67822
|
+
* amount in the bowl is `bowlFood`. On dual-hopper models this is the
|
|
67823
|
+
* combined reading; per-hopper levels live in `food1`/`food2`. Null when
|
|
67824
|
+
* the device has not reported yet. */
|
|
67363
67825
|
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
67826
|
+
/** Food in the BOWL as the feeder reports it (`state.bowl`), in the
|
|
67827
|
+
* feeder's own units. Null when the model reports none. */
|
|
67828
|
+
bowlFood: number().nullable().meta(readingMeta("none")),
|
|
67829
|
+
/** True while the pet is eating (`state.eating`). */
|
|
67830
|
+
eating: boolean(),
|
|
67831
|
+
/** Whether `markFoodReplenished` does anything on this model. When false
|
|
67832
|
+
* the client must not offer it. */
|
|
67833
|
+
supportsMarkRefilled: boolean(),
|
|
67364
67834
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
67365
67835
|
* single-hopper models. */
|
|
67366
67836
|
food1: number().nullable().meta(readingMeta("none")),
|
|
@@ -67368,8 +67838,8 @@ var PetFeederStatusSchema = object({
|
|
|
67368
67838
|
* single-hopper models. */
|
|
67369
67839
|
food2: number().nullable().meta(readingMeta("none")),
|
|
67370
67840
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
67371
|
-
* (`device_class: problem`, on = low). True when the
|
|
67372
|
-
*
|
|
67841
|
+
* (`device_class: problem`, on = low). True when the tank reports empty,
|
|
67842
|
+
* or, on a dual-hopper model, when EITHER hopper is empty. */
|
|
67373
67843
|
lowFood: boolean(),
|
|
67374
67844
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
67375
67845
|
* device has no battery reading. */
|
|
@@ -67437,7 +67907,9 @@ var petFeederCapability = {
|
|
|
67437
67907
|
kind: "mutation",
|
|
67438
67908
|
auth: "protected"
|
|
67439
67909
|
}),
|
|
67440
|
-
/**
|
|
67910
|
+
/** Tell the PetKit cloud a hopper was refilled so it stops its low-food
|
|
67911
|
+
* reminders (D4H/D4S/D4SH only — see `supportsMarkRefilled`). It does not
|
|
67912
|
+
* change any sensor reading. */
|
|
67441
67913
|
markFoodReplenished: method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
67442
67914
|
kind: "mutation",
|
|
67443
67915
|
auth: "protected"
|
|
@@ -67510,6 +67982,7 @@ var petFeederCapability = {
|
|
|
67510
67982
|
*/
|
|
67511
67983
|
history: { fields: {
|
|
67512
67984
|
foodLevel: { kind: "gauge" },
|
|
67985
|
+
bowlFood: { kind: "gauge" },
|
|
67513
67986
|
food1: { kind: "gauge" },
|
|
67514
67987
|
food2: { kind: "gauge" },
|
|
67515
67988
|
batteryPower: {
|
|
@@ -67959,9 +68432,9 @@ var PowerMeterStatusSchema = object({
|
|
|
67959
68432
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
67960
68433
|
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
67961
68434
|
/** Voltage in volts. */
|
|
67962
|
-
volts: number().optional().meta(readingMeta("voltage")),
|
|
68435
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
67963
68436
|
/** Current in amperes. */
|
|
67964
|
-
amps: number().optional().meta(readingMeta("current")),
|
|
68437
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
67965
68438
|
/** Apparent power in volt-amperes. */
|
|
67966
68439
|
va: number().optional().meta(readingMeta("apparent-power")),
|
|
67967
68440
|
/** Power factor (0..1) if reported. */
|
|
@@ -67969,17 +68442,74 @@ var PowerMeterStatusSchema = object({
|
|
|
67969
68442
|
/** Ms epoch when the slice was last updated. */
|
|
67970
68443
|
lastFetchedAt: number()
|
|
67971
68444
|
});
|
|
68445
|
+
/**
|
|
68446
|
+
* Loads that draw metered mains power (D951). The reading is a feature of the
|
|
68447
|
+
* device itself — a plug, a lamp, a fan, an air conditioner, a boiler, a
|
|
68448
|
+
* vacuum dock — not a separate sensor beside it. A `Sensor` stays: a clamp
|
|
68449
|
+
* meter or a standalone energy monitor IS the device. Cover, lock, valve,
|
|
68450
|
+
* camera and the like are left out: their draw is not what anyone meters.
|
|
68451
|
+
*/
|
|
68452
|
+
var POWER_METER_DEVICE_TYPES = [
|
|
68453
|
+
DeviceType.Sensor,
|
|
68454
|
+
DeviceType.Switch,
|
|
68455
|
+
DeviceType.Light,
|
|
68456
|
+
DeviceType.Fan,
|
|
68457
|
+
DeviceType.Climate,
|
|
68458
|
+
DeviceType.Thermostat,
|
|
68459
|
+
DeviceType.Humidifier,
|
|
68460
|
+
DeviceType.WaterHeater,
|
|
68461
|
+
DeviceType.MediaPlayer,
|
|
68462
|
+
DeviceType.Washer,
|
|
68463
|
+
DeviceType.Dryer,
|
|
68464
|
+
DeviceType.Dishwasher,
|
|
68465
|
+
DeviceType.Vacuum,
|
|
68466
|
+
DeviceType.LawnMower,
|
|
68467
|
+
DeviceType.PetFeeder
|
|
68468
|
+
];
|
|
68469
|
+
/** Everything but a bare `Sensor`: a sensor that takes its reading from another sensor adds nothing. */
|
|
68470
|
+
var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== DeviceType.Sensor);
|
|
68471
|
+
/** One scalar target per reading; each is sourced from a device of its own (D951). */
|
|
68472
|
+
function powerTarget(id, unit) {
|
|
68473
|
+
return {
|
|
68474
|
+
id,
|
|
68475
|
+
cardinality: "scalar",
|
|
68476
|
+
vocabulary: {
|
|
68477
|
+
cap: "power-meter",
|
|
68478
|
+
stateField: id
|
|
68479
|
+
},
|
|
68480
|
+
deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
|
|
68481
|
+
apply: "add",
|
|
68482
|
+
path: id,
|
|
68483
|
+
sources: [{
|
|
68484
|
+
kind: "numeric",
|
|
68485
|
+
requiredUnit: unit,
|
|
68486
|
+
transforms: [{ kind: "identity" }]
|
|
68487
|
+
}],
|
|
68488
|
+
companions: [{
|
|
68489
|
+
kind: "clock",
|
|
68490
|
+
path: "lastFetchedAt",
|
|
68491
|
+
when: "always"
|
|
68492
|
+
}],
|
|
68493
|
+
sourceReport: { status: "assignment-status" },
|
|
68494
|
+
advancedExpression: true
|
|
68495
|
+
};
|
|
68496
|
+
}
|
|
68497
|
+
/** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
|
|
68498
|
+
var powerMeterCustomize = {
|
|
68499
|
+
version: 1,
|
|
68500
|
+
targets: [
|
|
68501
|
+
powerTarget("watts", "W"),
|
|
68502
|
+
powerTarget("kwhTotal", "kWh"),
|
|
68503
|
+
powerTarget("volts", "V"),
|
|
68504
|
+
powerTarget("amps", "A")
|
|
68505
|
+
]
|
|
68506
|
+
};
|
|
67972
68507
|
var powerMeterCapability = {
|
|
67973
68508
|
name: "power-meter",
|
|
67974
68509
|
scope: "device",
|
|
67975
68510
|
deviceNative: true,
|
|
67976
68511
|
mode: "singleton",
|
|
67977
|
-
deviceTypes:
|
|
67978
|
-
DeviceType.Sensor,
|
|
67979
|
-
DeviceType.Washer,
|
|
67980
|
-
DeviceType.Dryer,
|
|
67981
|
-
DeviceType.Dishwasher
|
|
67982
|
-
],
|
|
68512
|
+
deviceTypes: POWER_METER_DEVICE_TYPES,
|
|
67983
68513
|
methods: {},
|
|
67984
68514
|
status: {
|
|
67985
68515
|
schema: PowerMeterStatusSchema,
|
|
@@ -68036,7 +68566,8 @@ var powerMeterCapability = {
|
|
|
68036
68566
|
} },
|
|
68037
68567
|
/** Clock fields: written, but excluded from the compare that decides
|
|
68038
68568
|
* whether persisting is worth a SQLite commit. */
|
|
68039
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
68569
|
+
volatileStateFields: ["lastFetchedAt"],
|
|
68570
|
+
customize: powerMeterCustomize
|
|
68040
68571
|
};
|
|
68041
68572
|
/**
|
|
68042
68573
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -73474,7 +74005,7 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
73474
74005
|
});
|
|
73475
74006
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
73476
74007
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
73477
|
-
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;
|
|
74008
|
+
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;
|
|
73478
74009
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
73479
74010
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
73480
74011
|
new Set(CAP_NAMES);
|
|
@@ -74662,6 +75193,104 @@ Object.freeze({
|
|
|
74662
75193
|
access: "create",
|
|
74663
75194
|
role: "admin"
|
|
74664
75195
|
},
|
|
75196
|
+
"actions.create": {
|
|
75197
|
+
capName: "actions",
|
|
75198
|
+
capScope: "system",
|
|
75199
|
+
addonId: null,
|
|
75200
|
+
access: "create",
|
|
75201
|
+
role: "admin"
|
|
75202
|
+
},
|
|
75203
|
+
"actions.delete": {
|
|
75204
|
+
capName: "actions",
|
|
75205
|
+
capScope: "system",
|
|
75206
|
+
addonId: null,
|
|
75207
|
+
access: "delete",
|
|
75208
|
+
role: "admin"
|
|
75209
|
+
},
|
|
75210
|
+
"actions.get": {
|
|
75211
|
+
capName: "actions",
|
|
75212
|
+
capScope: "system",
|
|
75213
|
+
addonId: null,
|
|
75214
|
+
access: "view",
|
|
75215
|
+
role: "viewer"
|
|
75216
|
+
},
|
|
75217
|
+
"actions.getLinks": {
|
|
75218
|
+
capName: "actions",
|
|
75219
|
+
capScope: "system",
|
|
75220
|
+
addonId: null,
|
|
75221
|
+
access: "view",
|
|
75222
|
+
role: "admin"
|
|
75223
|
+
},
|
|
75224
|
+
"actions.getTraces": {
|
|
75225
|
+
capName: "actions",
|
|
75226
|
+
capScope: "system",
|
|
75227
|
+
addonId: null,
|
|
75228
|
+
access: "view",
|
|
75229
|
+
role: "admin"
|
|
75230
|
+
},
|
|
75231
|
+
"actions.list": {
|
|
75232
|
+
capName: "actions",
|
|
75233
|
+
capScope: "system",
|
|
75234
|
+
addonId: null,
|
|
75235
|
+
access: "view",
|
|
75236
|
+
role: "admin"
|
|
75237
|
+
},
|
|
75238
|
+
"actions.listForCamera": {
|
|
75239
|
+
capName: "actions",
|
|
75240
|
+
capScope: "system",
|
|
75241
|
+
addonId: null,
|
|
75242
|
+
access: "view",
|
|
75243
|
+
role: "viewer"
|
|
75244
|
+
},
|
|
75245
|
+
"actions.run": {
|
|
75246
|
+
capName: "actions",
|
|
75247
|
+
capScope: "system",
|
|
75248
|
+
addonId: null,
|
|
75249
|
+
access: "create",
|
|
75250
|
+
role: "viewer"
|
|
75251
|
+
},
|
|
75252
|
+
"actions.setLinks": {
|
|
75253
|
+
capName: "actions",
|
|
75254
|
+
capScope: "system",
|
|
75255
|
+
addonId: null,
|
|
75256
|
+
access: "create",
|
|
75257
|
+
role: "admin"
|
|
75258
|
+
},
|
|
75259
|
+
"actions.stop": {
|
|
75260
|
+
capName: "actions",
|
|
75261
|
+
capScope: "system",
|
|
75262
|
+
addonId: null,
|
|
75263
|
+
access: "create",
|
|
75264
|
+
role: "admin"
|
|
75265
|
+
},
|
|
75266
|
+
"actions.update": {
|
|
75267
|
+
capName: "actions",
|
|
75268
|
+
capScope: "system",
|
|
75269
|
+
addonId: null,
|
|
75270
|
+
access: "create",
|
|
75271
|
+
role: "admin"
|
|
75272
|
+
},
|
|
75273
|
+
"actionSource.listActions": {
|
|
75274
|
+
capName: "action-source",
|
|
75275
|
+
capScope: "system",
|
|
75276
|
+
addonId: null,
|
|
75277
|
+
access: "view",
|
|
75278
|
+
role: "admin"
|
|
75279
|
+
},
|
|
75280
|
+
"actionSource.runAction": {
|
|
75281
|
+
capName: "action-source",
|
|
75282
|
+
capScope: "system",
|
|
75283
|
+
addonId: null,
|
|
75284
|
+
access: "create",
|
|
75285
|
+
role: "admin"
|
|
75286
|
+
},
|
|
75287
|
+
"actionSource.stopAction": {
|
|
75288
|
+
capName: "action-source",
|
|
75289
|
+
capScope: "system",
|
|
75290
|
+
addonId: null,
|
|
75291
|
+
access: "create",
|
|
75292
|
+
role: "admin"
|
|
75293
|
+
},
|
|
74665
75294
|
"addonPages.listPages": {
|
|
74666
75295
|
capName: "addon-pages",
|
|
74667
75296
|
capScope: "system",
|
|
@@ -75943,6 +76572,13 @@ Object.freeze({
|
|
|
75943
76572
|
access: "view",
|
|
75944
76573
|
role: "admin"
|
|
75945
76574
|
},
|
|
76575
|
+
"coreBlocks.getAutomationRunState": {
|
|
76576
|
+
capName: "core-blocks",
|
|
76577
|
+
capScope: "system",
|
|
76578
|
+
addonId: null,
|
|
76579
|
+
access: "view",
|
|
76580
|
+
role: "admin"
|
|
76581
|
+
},
|
|
75946
76582
|
"coreBlocks.getBlockSettings": {
|
|
75947
76583
|
capName: "core-blocks",
|
|
75948
76584
|
capScope: "system",
|
|
@@ -75964,6 +76600,13 @@ Object.freeze({
|
|
|
75964
76600
|
access: "view",
|
|
75965
76601
|
role: "admin"
|
|
75966
76602
|
},
|
|
76603
|
+
"coreBlocks.getTraces": {
|
|
76604
|
+
capName: "core-blocks",
|
|
76605
|
+
capScope: "system",
|
|
76606
|
+
addonId: null,
|
|
76607
|
+
access: "view",
|
|
76608
|
+
role: "admin"
|
|
76609
|
+
},
|
|
75967
76610
|
"coreBlocks.getTypeDefs": {
|
|
75968
76611
|
capName: "core-blocks",
|
|
75969
76612
|
capScope: "system",
|
|
@@ -75999,6 +76642,13 @@ Object.freeze({
|
|
|
75999
76642
|
access: "create",
|
|
76000
76643
|
role: "admin"
|
|
76001
76644
|
},
|
|
76645
|
+
"coreBlocks.reportAutomationRun": {
|
|
76646
|
+
capName: "core-blocks",
|
|
76647
|
+
capScope: "system",
|
|
76648
|
+
addonId: null,
|
|
76649
|
+
access: "create",
|
|
76650
|
+
role: "admin"
|
|
76651
|
+
},
|
|
76002
76652
|
"coreBlocks.restart": {
|
|
76003
76653
|
capName: "core-blocks",
|
|
76004
76654
|
capScope: "system",
|
|
@@ -88153,6 +88803,8 @@ var ML = "model and training machinery — no device action";
|
|
|
88153
88803
|
var INTERNAL = "internal plumbing between addons — never operator-facing";
|
|
88154
88804
|
/** Every system-scoped cap, with why it is not a device's vocabulary. */
|
|
88155
88805
|
var SYSTEM_CAP_VOCABULARY = {
|
|
88806
|
+
"action-source": system(INTERNAL),
|
|
88807
|
+
actions: system("declared actions — run from the Actions page and from the cameras that link them"),
|
|
88156
88808
|
"addon-pages": system(UI_PLUMBING),
|
|
88157
88809
|
"addon-pages-source": system(UI_PLUMBING),
|
|
88158
88810
|
"addon-routes": system(UI_PLUMBING),
|
|
@@ -88349,6 +89001,31 @@ Object.freeze({
|
|
|
88349
89001
|
form: "single",
|
|
88350
89002
|
optional: false
|
|
88351
89003
|
}],
|
|
89004
|
+
"actions.get": [{
|
|
89005
|
+
name: "deviceId",
|
|
89006
|
+
form: "single",
|
|
89007
|
+
optional: true
|
|
89008
|
+
}],
|
|
89009
|
+
"actions.getLinks": [{
|
|
89010
|
+
name: "deviceId",
|
|
89011
|
+
form: "single",
|
|
89012
|
+
optional: false
|
|
89013
|
+
}],
|
|
89014
|
+
"actions.listForCamera": [{
|
|
89015
|
+
name: "deviceId",
|
|
89016
|
+
form: "single",
|
|
89017
|
+
optional: false
|
|
89018
|
+
}],
|
|
89019
|
+
"actions.run": [{
|
|
89020
|
+
name: "deviceId",
|
|
89021
|
+
form: "single",
|
|
89022
|
+
optional: true
|
|
89023
|
+
}],
|
|
89024
|
+
"actions.setLinks": [{
|
|
89025
|
+
name: "deviceId",
|
|
89026
|
+
form: "single",
|
|
89027
|
+
optional: false
|
|
89028
|
+
}],
|
|
88352
89029
|
"addonSettings.getDeviceSettings": [{
|
|
88353
89030
|
name: "deviceId",
|
|
88354
89031
|
form: "single",
|
|
@@ -95549,6 +96226,7 @@ function cosineSimilarity(a, b) {
|
|
|
95549
96226
|
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
95550
96227
|
return denom === 0 ? 0 : dotProduct / denom;
|
|
95551
96228
|
}
|
|
96229
|
+
String.raw`(?<=^|["'(\s>,\[{])`;
|
|
95552
96230
|
var MB = 1024 * 1024;
|
|
95553
96231
|
var DEFAULT_POOL_MEMORY_POLICY = {
|
|
95554
96232
|
sampleIntervalMs: 6e4,
|