@camstack/addon-waste-collections 0.1.31 → 0.1.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/waste-collections.addon.js +2371 -668
- package/dist/waste-collections.addon.mjs +2371 -668
- package/package.json +3 -2
|
@@ -6,7 +6,7 @@ let node_fs = require("node:fs");
|
|
|
6
6
|
let node_path = require("node:path");
|
|
7
7
|
let node_child_process = require("node:child_process");
|
|
8
8
|
let node_url = require("node:url");
|
|
9
|
-
//#region ../types/dist/event-category-
|
|
9
|
+
//#region ../types/dist/event-category-DmZDPDf_.mjs
|
|
10
10
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
11
11
|
EventCategory["SystemBoot"] = "system.boot";
|
|
12
12
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -633,7 +633,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
633
633
|
* (a track was promoted to a stationary-registry entry) or departs (the
|
|
634
634
|
* object moved / was removed). Telemetry (D8): lossy, drives a UI refresh of
|
|
635
635
|
* the dedicated "Stationary" section — never the live event feed. Payload:
|
|
636
|
-
* `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp }`.
|
|
636
|
+
* `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp, observedAt, zones }`.
|
|
637
637
|
*/
|
|
638
638
|
EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
|
|
639
639
|
/**
|
|
@@ -771,6 +771,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
771
771
|
*/
|
|
772
772
|
EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
|
|
773
773
|
/**
|
|
774
|
+
* An action run started or ended. Emitted by the `actions` surface.
|
|
775
|
+
* Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
|
|
776
|
+
*/
|
|
777
|
+
EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
|
|
778
|
+
/**
|
|
774
779
|
* Progress update from a running model conversion job.
|
|
775
780
|
* Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
|
|
776
781
|
* Emitted by `addon-model-studio` on the converting node.
|
|
@@ -5203,6 +5208,14 @@ function object(shape, params) {
|
|
|
5203
5208
|
...normalizeParams(params)
|
|
5204
5209
|
});
|
|
5205
5210
|
}
|
|
5211
|
+
function strictObject(shape, params) {
|
|
5212
|
+
return new ZodObject({
|
|
5213
|
+
type: "object",
|
|
5214
|
+
shape,
|
|
5215
|
+
catchall: never(),
|
|
5216
|
+
...normalizeParams(params)
|
|
5217
|
+
});
|
|
5218
|
+
}
|
|
5206
5219
|
function looseObject(shape, params) {
|
|
5207
5220
|
return new ZodObject({
|
|
5208
5221
|
type: "object",
|
|
@@ -5582,7 +5595,7 @@ var ZodIssueCode = {
|
|
|
5582
5595
|
var ZodFirstPartyTypeKind;
|
|
5583
5596
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5584
5597
|
//#endregion
|
|
5585
|
-
//#region ../types/dist/sleep
|
|
5598
|
+
//#region ../types/dist/sleep-6eG9C8Xl.mjs
|
|
5586
5599
|
/**
|
|
5587
5600
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5588
5601
|
* window to float samples (D455).
|
|
@@ -8823,6 +8836,52 @@ function optionalMethod(input, output, options) {
|
|
|
8823
8836
|
providerOptional: true
|
|
8824
8837
|
};
|
|
8825
8838
|
}
|
|
8839
|
+
/**
|
|
8840
|
+
* `addon-pages-source` — collection cap exposing per-provider raw page
|
|
8841
|
+
* declarations. Every addon that contributes a UI page registers a
|
|
8842
|
+
* provider here. The hub-side singleton aggregator (`addon-pages` cap,
|
|
8843
|
+
* see `addon-pages.cap.ts`) walks this collection, stamps versioned
|
|
8844
|
+
* `bundleUrl` values, and returns the enriched `AddonPageInfo[]` list
|
|
8845
|
+
* that admin-ui consumes.
|
|
8846
|
+
*
|
|
8847
|
+
* The split exists because the public listing has a different output
|
|
8848
|
+
* shape than the per-provider raw declarations, and we want both ends
|
|
8849
|
+
* to flow through codegen instead of relying on a hand-written wrapper.
|
|
8850
|
+
*/
|
|
8851
|
+
var AddonPageDeclarationSchema = object({
|
|
8852
|
+
id: string(),
|
|
8853
|
+
label: string(),
|
|
8854
|
+
icon: string(),
|
|
8855
|
+
path: string(),
|
|
8856
|
+
/**
|
|
8857
|
+
* Module Federation remote name — must match the `name` field on the
|
|
8858
|
+
* page addon's `federation()` plugin config. Used by admin-ui's
|
|
8859
|
+
* `<AddonPageLoader>` to call `loadRemote('<remoteName>/page')`.
|
|
8860
|
+
* Conventionally `addon_<id>_page` (snake_case; MF names cannot
|
|
8861
|
+
* contain hyphens).
|
|
8862
|
+
*/
|
|
8863
|
+
remoteName: string(),
|
|
8864
|
+
/**
|
|
8865
|
+
* Bundle filename inside the addon's `dist/` dir served at
|
|
8866
|
+
* `/api/addon-pages/<addonId>/<bundle>`. With Module Federation this
|
|
8867
|
+
* is always `'remoteEntry.js'`; the value is kept on the metadata so
|
|
8868
|
+
* the static-file route can compute an mtime-based cache-buster URL
|
|
8869
|
+
* without a separate filesystem stat.
|
|
8870
|
+
*/
|
|
8871
|
+
bundle: string(),
|
|
8872
|
+
/**
|
|
8873
|
+
* Sidebar section this page docks into. Well-known ids: `'detection'`,
|
|
8874
|
+
* `'cluster'`, `'administration'` — the page renders inside that group.
|
|
8875
|
+
* Any OTHER string creates (or joins) a custom section rendered after
|
|
8876
|
+
* the built-in groups; its label comes from `sectionLabel` (first
|
|
8877
|
+
* declaration wins), falling back to the id. Absent → the legacy
|
|
8878
|
+
* "Addon Pages" group.
|
|
8879
|
+
*/
|
|
8880
|
+
section: string().optional(),
|
|
8881
|
+
/** Display label for a CUSTOM `section` id (ignored for well-known ids). */
|
|
8882
|
+
sectionLabel: string().optional()
|
|
8883
|
+
});
|
|
8884
|
+
method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
|
|
8826
8885
|
var StaticDirOutputSchema$1 = object({ staticDir: string() });
|
|
8827
8886
|
var VersionOutputSchema$1 = object({ version: string() });
|
|
8828
8887
|
method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
|
|
@@ -8848,6 +8907,27 @@ function customAction(input, output, options) {
|
|
|
8848
8907
|
...options?.caller ? { caller: "required" } : {}
|
|
8849
8908
|
};
|
|
8850
8909
|
}
|
|
8910
|
+
/**
|
|
8911
|
+
* The pipeline step-input shape and the run-result bridge, in a module that
|
|
8912
|
+
* imports nothing but zod and types.
|
|
8913
|
+
*
|
|
8914
|
+
* WHY A SEPARATE FILE (addon footprint, D28): both were declared in
|
|
8915
|
+
* `pipeline-executor.cap.ts`, whose import evaluates the whole executor schema
|
|
8916
|
+
* graph. An addon that only needs these two (the benchmark's `runPipelineTest`
|
|
8917
|
+
* action) paid ~130 MB of heap at load. `pipeline-executor.cap.ts` re-exports
|
|
8918
|
+
* them, so every existing import keeps working; addon server code takes them
|
|
8919
|
+
* from `@camstack/types/addon`.
|
|
8920
|
+
*/
|
|
8921
|
+
var PipelineStepInputSchema = lazy(() => object({
|
|
8922
|
+
addonId: string(),
|
|
8923
|
+
modelId: string().optional(),
|
|
8924
|
+
enabled: boolean().default(true),
|
|
8925
|
+
children: array(PipelineStepInputSchema).optional(),
|
|
8926
|
+
settings: record(string(), unknown()).optional(),
|
|
8927
|
+
jumpDeviceKey: string().optional()
|
|
8928
|
+
}));
|
|
8929
|
+
/** Typed bridge to the recursive `FrameResult` graph; validation is structural. */
|
|
8930
|
+
var PipelineRunResultBridge = custom();
|
|
8851
8931
|
var StaticDirOutputSchema = object({ staticDir: string() });
|
|
8852
8932
|
var VersionOutputSchema = object({ version: string() });
|
|
8853
8933
|
method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
|
|
@@ -8918,6 +8998,8 @@ Object.freeze({ "doorbell": "lastPressedAt" });
|
|
|
8918
8998
|
/** Every capability name, so addon code can check a name without the schema graph. */
|
|
8919
8999
|
var CAP_NAMES = Object.freeze([
|
|
8920
9000
|
"accessories",
|
|
9001
|
+
"action-source",
|
|
9002
|
+
"actions",
|
|
8921
9003
|
"addon-pages",
|
|
8922
9004
|
"addon-pages-source",
|
|
8923
9005
|
"addon-routes",
|
|
@@ -9001,6 +9083,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9001
9083
|
"image-settings",
|
|
9002
9084
|
"integrations",
|
|
9003
9085
|
"intercom",
|
|
9086
|
+
"ir-transmitter",
|
|
9004
9087
|
"keychain",
|
|
9005
9088
|
"keychain-admin",
|
|
9006
9089
|
"lawn-mower-control",
|
|
@@ -9029,6 +9112,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9029
9112
|
"network-link",
|
|
9030
9113
|
"network-quality",
|
|
9031
9114
|
"node-certificates",
|
|
9115
|
+
"node-removal-hook",
|
|
9032
9116
|
"nodes",
|
|
9033
9117
|
"notification-output",
|
|
9034
9118
|
"notification-rules",
|
|
@@ -9039,6 +9123,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9039
9123
|
"osd",
|
|
9040
9124
|
"osd-manager",
|
|
9041
9125
|
"pet-feeder",
|
|
9126
|
+
"pet-fountain",
|
|
9042
9127
|
"pipeline-analytics",
|
|
9043
9128
|
"pipeline-executor",
|
|
9044
9129
|
"pipeline-orchestrator",
|
|
@@ -9059,6 +9144,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9059
9144
|
"recording-onboard",
|
|
9060
9145
|
"recording-signal",
|
|
9061
9146
|
"records",
|
|
9147
|
+
"remote",
|
|
9062
9148
|
"running-state",
|
|
9063
9149
|
"scene-monitor",
|
|
9064
9150
|
"script-runner",
|
|
@@ -9082,6 +9168,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9082
9168
|
"system",
|
|
9083
9169
|
"tamper",
|
|
9084
9170
|
"temperature-sensor",
|
|
9171
|
+
"template",
|
|
9085
9172
|
"terminal-session",
|
|
9086
9173
|
"toast",
|
|
9087
9174
|
"training",
|
|
@@ -9106,11 +9193,11 @@ var CAP_NAMES = Object.freeze([
|
|
|
9106
9193
|
Object.freeze({
|
|
9107
9194
|
"air-quality-sensor": [
|
|
9108
9195
|
{
|
|
9109
|
-
"path": "
|
|
9196
|
+
"path": "co2",
|
|
9110
9197
|
"valueType": "number"
|
|
9111
9198
|
},
|
|
9112
9199
|
{
|
|
9113
|
-
"path": "
|
|
9200
|
+
"path": "voc",
|
|
9114
9201
|
"valueType": "number"
|
|
9115
9202
|
},
|
|
9116
9203
|
{
|
|
@@ -9160,7 +9247,7 @@ Object.freeze({
|
|
|
9160
9247
|
}
|
|
9161
9248
|
],
|
|
9162
9249
|
"ambient-light-sensor": [{
|
|
9163
|
-
"path": "
|
|
9250
|
+
"path": "illuminance",
|
|
9164
9251
|
"valueType": "number"
|
|
9165
9252
|
}],
|
|
9166
9253
|
"audio-metrics": [
|
|
@@ -9221,7 +9308,7 @@ Object.freeze({
|
|
|
9221
9308
|
],
|
|
9222
9309
|
"battery": [
|
|
9223
9310
|
{
|
|
9224
|
-
"path": "
|
|
9311
|
+
"path": "level",
|
|
9225
9312
|
"valueType": "number"
|
|
9226
9313
|
},
|
|
9227
9314
|
{
|
|
@@ -9243,7 +9330,7 @@ Object.freeze({
|
|
|
9243
9330
|
"valueType": "number"
|
|
9244
9331
|
},
|
|
9245
9332
|
{
|
|
9246
|
-
"path": "
|
|
9333
|
+
"path": "voltage",
|
|
9247
9334
|
"valueType": "number"
|
|
9248
9335
|
},
|
|
9249
9336
|
{
|
|
@@ -9264,7 +9351,7 @@ Object.freeze({
|
|
|
9264
9351
|
"valueType": "boolean"
|
|
9265
9352
|
}],
|
|
9266
9353
|
"brightness": [{
|
|
9267
|
-
"path": "
|
|
9354
|
+
"path": "level",
|
|
9268
9355
|
"valueType": "number"
|
|
9269
9356
|
}],
|
|
9270
9357
|
"broker": [{
|
|
@@ -9465,7 +9552,7 @@ Object.freeze({
|
|
|
9465
9552
|
"valueType": "number"
|
|
9466
9553
|
},
|
|
9467
9554
|
{
|
|
9468
|
-
"path": "
|
|
9555
|
+
"path": "colorTemperature",
|
|
9469
9556
|
"valueType": "number"
|
|
9470
9557
|
}
|
|
9471
9558
|
],
|
|
@@ -9644,15 +9731,15 @@ Object.freeze({
|
|
|
9644
9731
|
"valueType": "string"
|
|
9645
9732
|
},
|
|
9646
9733
|
{
|
|
9647
|
-
"path": "
|
|
9734
|
+
"path": "remaining",
|
|
9648
9735
|
"valueType": "number"
|
|
9649
9736
|
},
|
|
9650
9737
|
{
|
|
9651
|
-
"path": "
|
|
9738
|
+
"path": "delayedStart",
|
|
9652
9739
|
"valueType": "number"
|
|
9653
9740
|
},
|
|
9654
9741
|
{
|
|
9655
|
-
"path": "
|
|
9742
|
+
"path": "progress",
|
|
9656
9743
|
"valueType": "number"
|
|
9657
9744
|
},
|
|
9658
9745
|
{
|
|
@@ -9766,7 +9853,7 @@ Object.freeze({
|
|
|
9766
9853
|
],
|
|
9767
9854
|
"fan-control": [
|
|
9768
9855
|
{
|
|
9769
|
-
"path": "
|
|
9856
|
+
"path": "speed",
|
|
9770
9857
|
"valueType": "number"
|
|
9771
9858
|
},
|
|
9772
9859
|
{
|
|
@@ -9866,7 +9953,7 @@ Object.freeze({
|
|
|
9866
9953
|
}
|
|
9867
9954
|
],
|
|
9868
9955
|
"humidity-sensor": [{
|
|
9869
|
-
"path": "
|
|
9956
|
+
"path": "humidity",
|
|
9870
9957
|
"valueType": "number"
|
|
9871
9958
|
}],
|
|
9872
9959
|
"image": [{
|
|
@@ -9976,7 +10063,7 @@ Object.freeze({
|
|
|
9976
10063
|
"valueType": "number"
|
|
9977
10064
|
},
|
|
9978
10065
|
{
|
|
9979
|
-
"path": "
|
|
10066
|
+
"path": "progress",
|
|
9980
10067
|
"valueType": "number"
|
|
9981
10068
|
},
|
|
9982
10069
|
{
|
|
@@ -10022,6 +10109,11 @@ Object.freeze({
|
|
|
10022
10109
|
"standby"
|
|
10023
10110
|
]
|
|
10024
10111
|
},
|
|
10112
|
+
{
|
|
10113
|
+
"path": "stateSource",
|
|
10114
|
+
"valueType": "enum",
|
|
10115
|
+
"enumValues": ["reported", "assumed"]
|
|
10116
|
+
},
|
|
10025
10117
|
{
|
|
10026
10118
|
"path": "volumeLevel",
|
|
10027
10119
|
"valueType": "number"
|
|
@@ -10055,11 +10147,11 @@ Object.freeze({
|
|
|
10055
10147
|
"valueType": "string"
|
|
10056
10148
|
},
|
|
10057
10149
|
{
|
|
10058
|
-
"path": "
|
|
10150
|
+
"path": "position",
|
|
10059
10151
|
"valueType": "number"
|
|
10060
10152
|
},
|
|
10061
10153
|
{
|
|
10062
|
-
"path": "
|
|
10154
|
+
"path": "duration",
|
|
10063
10155
|
"valueType": "number"
|
|
10064
10156
|
},
|
|
10065
10157
|
{
|
|
@@ -10161,11 +10253,11 @@ Object.freeze({
|
|
|
10161
10253
|
]
|
|
10162
10254
|
},
|
|
10163
10255
|
{
|
|
10164
|
-
"path": "
|
|
10256
|
+
"path": "signal",
|
|
10165
10257
|
"valueType": "number"
|
|
10166
10258
|
},
|
|
10167
10259
|
{
|
|
10168
|
-
"path": "
|
|
10260
|
+
"path": "rssi",
|
|
10169
10261
|
"valueType": "number"
|
|
10170
10262
|
},
|
|
10171
10263
|
{
|
|
@@ -10220,6 +10312,18 @@ Object.freeze({
|
|
|
10220
10312
|
"path": "foodLevel",
|
|
10221
10313
|
"valueType": "number"
|
|
10222
10314
|
},
|
|
10315
|
+
{
|
|
10316
|
+
"path": "bowlFood",
|
|
10317
|
+
"valueType": "number"
|
|
10318
|
+
},
|
|
10319
|
+
{
|
|
10320
|
+
"path": "eating",
|
|
10321
|
+
"valueType": "boolean"
|
|
10322
|
+
},
|
|
10323
|
+
{
|
|
10324
|
+
"path": "supportsMarkRefilled",
|
|
10325
|
+
"valueType": "boolean"
|
|
10326
|
+
},
|
|
10223
10327
|
{
|
|
10224
10328
|
"path": "food1",
|
|
10225
10329
|
"valueType": "number"
|
|
@@ -10236,6 +10340,11 @@ Object.freeze({
|
|
|
10236
10340
|
"path": "batteryPower",
|
|
10237
10341
|
"valueType": "number"
|
|
10238
10342
|
},
|
|
10343
|
+
{
|
|
10344
|
+
"path": "powerSource",
|
|
10345
|
+
"valueType": "enum",
|
|
10346
|
+
"enumValues": ["mains", "battery"]
|
|
10347
|
+
},
|
|
10239
10348
|
{
|
|
10240
10349
|
"path": "desiccantLeftDays",
|
|
10241
10350
|
"valueType": "number"
|
|
@@ -10280,27 +10389,89 @@ Object.freeze({
|
|
|
10280
10389
|
{
|
|
10281
10390
|
"path": "volume",
|
|
10282
10391
|
"valueType": "number"
|
|
10392
|
+
},
|
|
10393
|
+
{
|
|
10394
|
+
"path": "lastFeedGrams",
|
|
10395
|
+
"valueType": "number"
|
|
10396
|
+
},
|
|
10397
|
+
{
|
|
10398
|
+
"path": "lastFeedHopper1",
|
|
10399
|
+
"valueType": "number"
|
|
10400
|
+
},
|
|
10401
|
+
{
|
|
10402
|
+
"path": "lastFeedHopper2",
|
|
10403
|
+
"valueType": "number"
|
|
10404
|
+
}
|
|
10405
|
+
],
|
|
10406
|
+
"pet-fountain": [
|
|
10407
|
+
{
|
|
10408
|
+
"path": "waterLevel",
|
|
10409
|
+
"valueType": "number"
|
|
10410
|
+
},
|
|
10411
|
+
{
|
|
10412
|
+
"path": "waterVolume",
|
|
10413
|
+
"valueType": "number"
|
|
10414
|
+
},
|
|
10415
|
+
{
|
|
10416
|
+
"path": "empty",
|
|
10417
|
+
"valueType": "boolean"
|
|
10418
|
+
},
|
|
10419
|
+
{
|
|
10420
|
+
"path": "pumpRunning",
|
|
10421
|
+
"valueType": "boolean"
|
|
10422
|
+
},
|
|
10423
|
+
{
|
|
10424
|
+
"path": "pumpIntervalEnabled",
|
|
10425
|
+
"valueType": "boolean"
|
|
10426
|
+
},
|
|
10427
|
+
{
|
|
10428
|
+
"path": "pumpOnTime",
|
|
10429
|
+
"valueType": "number"
|
|
10430
|
+
},
|
|
10431
|
+
{
|
|
10432
|
+
"path": "pumpOffTime",
|
|
10433
|
+
"valueType": "number"
|
|
10434
|
+
},
|
|
10435
|
+
{
|
|
10436
|
+
"path": "lastDrink",
|
|
10437
|
+
"valueType": "number"
|
|
10438
|
+
},
|
|
10439
|
+
{
|
|
10440
|
+
"path": "currentHourDrink",
|
|
10441
|
+
"valueType": "number"
|
|
10442
|
+
},
|
|
10443
|
+
{
|
|
10444
|
+
"path": "last24hDrink",
|
|
10445
|
+
"valueType": "number"
|
|
10446
|
+
},
|
|
10447
|
+
{
|
|
10448
|
+
"path": "todayDrink",
|
|
10449
|
+
"valueType": "number"
|
|
10450
|
+
},
|
|
10451
|
+
{
|
|
10452
|
+
"path": "error",
|
|
10453
|
+
"valueType": "string"
|
|
10283
10454
|
}
|
|
10284
10455
|
],
|
|
10285
10456
|
"power-meter": [
|
|
10286
10457
|
{
|
|
10287
|
-
"path": "
|
|
10458
|
+
"path": "power",
|
|
10288
10459
|
"valueType": "number"
|
|
10289
10460
|
},
|
|
10290
10461
|
{
|
|
10291
|
-
"path": "
|
|
10462
|
+
"path": "energy",
|
|
10292
10463
|
"valueType": "number"
|
|
10293
10464
|
},
|
|
10294
10465
|
{
|
|
10295
|
-
"path": "
|
|
10466
|
+
"path": "voltage",
|
|
10296
10467
|
"valueType": "number"
|
|
10297
10468
|
},
|
|
10298
10469
|
{
|
|
10299
|
-
"path": "
|
|
10470
|
+
"path": "current",
|
|
10300
10471
|
"valueType": "number"
|
|
10301
10472
|
},
|
|
10302
10473
|
{
|
|
10303
|
-
"path": "
|
|
10474
|
+
"path": "apparentPower",
|
|
10304
10475
|
"valueType": "number"
|
|
10305
10476
|
},
|
|
10306
10477
|
{
|
|
@@ -10328,14 +10499,10 @@ Object.freeze({
|
|
|
10328
10499
|
{
|
|
10329
10500
|
"path": "gps.accuracyMeters",
|
|
10330
10501
|
"valueType": "number"
|
|
10331
|
-
},
|
|
10332
|
-
{
|
|
10333
|
-
"path": "batteryPercent",
|
|
10334
|
-
"valueType": "number"
|
|
10335
10502
|
}
|
|
10336
10503
|
],
|
|
10337
10504
|
"pressure-sensor": [{
|
|
10338
|
-
"path": "
|
|
10505
|
+
"path": "pressure",
|
|
10339
10506
|
"valueType": "number"
|
|
10340
10507
|
}],
|
|
10341
10508
|
"privacy-mask": [{
|
|
@@ -10649,7 +10816,7 @@ Object.freeze({
|
|
|
10649
10816
|
"valueType": "boolean"
|
|
10650
10817
|
}],
|
|
10651
10818
|
"temperature-sensor": [{
|
|
10652
|
-
"path": "
|
|
10819
|
+
"path": "temperature",
|
|
10653
10820
|
"valueType": "number"
|
|
10654
10821
|
}],
|
|
10655
10822
|
"update": [
|
|
@@ -10697,7 +10864,7 @@ Object.freeze({
|
|
|
10697
10864
|
"valueType": "string"
|
|
10698
10865
|
},
|
|
10699
10866
|
{
|
|
10700
|
-
"path": "
|
|
10867
|
+
"path": "progress",
|
|
10701
10868
|
"valueType": "number"
|
|
10702
10869
|
},
|
|
10703
10870
|
{
|
|
@@ -10823,7 +10990,7 @@ object({
|
|
|
10823
10990
|
params: record(string(), union([string(), number()])).optional()
|
|
10824
10991
|
});
|
|
10825
10992
|
//#endregion
|
|
10826
|
-
//#region ../types/dist/err-msg-
|
|
10993
|
+
//#region ../types/dist/err-msg-DWXWc0Di.mjs
|
|
10827
10994
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10828
10995
|
DeviceType["Camera"] = "camera";
|
|
10829
10996
|
DeviceType["Hub"] = "hub";
|
|
@@ -10915,6 +11082,10 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10915
11082
|
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
10916
11083
|
* integrations sharing the same food/desiccant/hopper surface. */
|
|
10917
11084
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
11085
|
+
/** Pet water fountain — tank level, water drunk, pump and its duty cycle.
|
|
11086
|
+
* Installed with the `pet-fountain` cap. Reaches CamStack as loose entities
|
|
11087
|
+
* of a container and is BUILT as a composed device (D967). */
|
|
11088
|
+
DeviceType["PetFountain"] = "pet-fountain";
|
|
10918
11089
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10919
11090
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10920
11091
|
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
@@ -11169,10 +11340,13 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
11169
11340
|
/** Fallback when the notifier service name doesn't match a known
|
|
11170
11341
|
* pattern. */
|
|
11171
11342
|
DeviceRole["GenericNotifier"] = "generic-notifier";
|
|
11343
|
+
/** Emits a pulse train (infrared or RF) on request — the `ir-transmitter`
|
|
11344
|
+
* cap. A `DeviceType.Generic` device. */
|
|
11345
|
+
DeviceRole["IrTransmitter"] = "ir-transmitter";
|
|
11172
11346
|
return DeviceRole;
|
|
11173
11347
|
}({});
|
|
11174
11348
|
//#endregion
|
|
11175
|
-
//#region ../types/dist/composition-
|
|
11349
|
+
//#region ../types/dist/composition-kSuOifuG.mjs
|
|
11176
11350
|
/**
|
|
11177
11351
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11178
11352
|
*
|
|
@@ -12257,12 +12431,28 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
|
12257
12431
|
])
|
|
12258
12432
|
})
|
|
12259
12433
|
]);
|
|
12260
|
-
var
|
|
12434
|
+
var forwardArgUnion = union([
|
|
12435
|
+
string(),
|
|
12436
|
+
number(),
|
|
12437
|
+
boolean(),
|
|
12438
|
+
strictObject({ ["$input"]: string().min(1) }),
|
|
12439
|
+
record(string().min(1), lazy(() => forwardArgUnion))
|
|
12440
|
+
]);
|
|
12441
|
+
var CompositionForwardArgSchema = forwardArgUnion;
|
|
12442
|
+
/**
|
|
12443
|
+
* `forward` (D659, amended by D967): one method of a BUILT capability is one
|
|
12444
|
+
* call of `cap.method` on `source`. Without `args` the built method's input
|
|
12445
|
+
* passes through minus `deviceId`; with `args` the template IS the source's
|
|
12446
|
+
* whole input. `deviceId` is always the source's own, never an argument.
|
|
12447
|
+
*/
|
|
12448
|
+
var CompositionForwardCommandSchema = object({
|
|
12261
12449
|
kind: literal("forward"),
|
|
12262
12450
|
source: CompositionSourceRefSchema,
|
|
12263
12451
|
cap: string().min(1),
|
|
12264
|
-
method: string().min(1)
|
|
12265
|
-
|
|
12452
|
+
method: string().min(1),
|
|
12453
|
+
args: record(string().min(1), CompositionForwardArgSchema).optional()
|
|
12454
|
+
});
|
|
12455
|
+
var CompositionCommandTargetSchema = discriminatedUnion("kind", [CompositionForwardCommandSchema, CompositionCodeSourceSchema]);
|
|
12266
12456
|
/** An item key inside an item-array cap (`consumables.items[<key>]`). */
|
|
12267
12457
|
var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
|
|
12268
12458
|
/**
|
|
@@ -12272,7 +12462,13 @@ var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
|
|
|
12272
12462
|
*/
|
|
12273
12463
|
var CompositionItemEntrySchema = object({
|
|
12274
12464
|
label: string().min(1).max(80),
|
|
12275
|
-
fields: record(string().min(1), CompositionFieldSourceSchema)
|
|
12465
|
+
fields: record(string().min(1), CompositionFieldSourceSchema),
|
|
12466
|
+
/**
|
|
12467
|
+
* What the cap's `reset` does for THIS item (consumables). Present = the item
|
|
12468
|
+
* is resettable and a `reset` call naming its key forwards here. The item key
|
|
12469
|
+
* selects the command, so it is never an argument: there is no pass-through.
|
|
12470
|
+
*/
|
|
12471
|
+
reset: CompositionForwardCommandSchema.optional()
|
|
12276
12472
|
});
|
|
12277
12473
|
var CompositionFeatureSchema = discriminatedUnion("kind", [object({
|
|
12278
12474
|
kind: literal("fields"),
|
|
@@ -12284,7 +12480,7 @@ var CompositionFeatureSchema = discriminatedUnion("kind", [object({
|
|
|
12284
12480
|
* owns the WHOLE array field: the composed value holds exactly these items.
|
|
12285
12481
|
*/
|
|
12286
12482
|
items: record(string().regex(COMPOSITION_ITEM_KEY_RE), CompositionItemEntrySchema).refine((items) => Object.keys(items).length <= 16, { message: `at most 16 items` }).optional(),
|
|
12287
|
-
/**
|
|
12483
|
+
/** Method name → what serves it. Only a BUILT capability takes commands (D967). */
|
|
12288
12484
|
commands: record(string().min(1), CompositionCommandTargetSchema).optional()
|
|
12289
12485
|
}), object({
|
|
12290
12486
|
kind: literal("passthrough"),
|
|
@@ -15692,6 +15888,14 @@ var AutomationConditionLeafSchema = object({
|
|
|
15692
15888
|
array(union([string(), number()]))
|
|
15693
15889
|
])
|
|
15694
15890
|
});
|
|
15891
|
+
var AutomationConditionStationaryPresentSchema = object({
|
|
15892
|
+
kind: literal("stationary-present"),
|
|
15893
|
+
deviceId: number().int().nonnegative(),
|
|
15894
|
+
/** Class names; a macro class matches every raw class that maps to it. */
|
|
15895
|
+
classes: array(string().min(1)).min(1).optional(),
|
|
15896
|
+
/** The parked object must be in at least one of these zones. */
|
|
15897
|
+
zones: array(string().min(1)).min(1).optional()
|
|
15898
|
+
});
|
|
15695
15899
|
/**
|
|
15696
15900
|
* The expression leaf, declared as a plain object rather than an intersection
|
|
15697
15901
|
* with {@link ExpressionSourceSchema}: a discriminated union has to be able to
|
|
@@ -15725,7 +15929,8 @@ var AutomationConditionSchema = lazy(() => discriminatedUnion("kind", [
|
|
|
15725
15929
|
child: AutomationConditionSchema
|
|
15726
15930
|
}),
|
|
15727
15931
|
AutomationConditionLeafSchema,
|
|
15728
|
-
AutomationConditionExpressionSchema
|
|
15932
|
+
AutomationConditionExpressionSchema,
|
|
15933
|
+
AutomationConditionStationaryPresentSchema
|
|
15729
15934
|
]));
|
|
15730
15935
|
/**
|
|
15731
15936
|
* What starts a run.
|
|
@@ -15766,7 +15971,34 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
|
|
|
15766
15971
|
kind: literal("schedule"),
|
|
15767
15972
|
cron: string().min(1).max(120)
|
|
15768
15973
|
}),
|
|
15769
|
-
object({ kind: literal("manual") })
|
|
15974
|
+
object({ kind: literal("manual") }),
|
|
15975
|
+
object({
|
|
15976
|
+
kind: literal("detection"),
|
|
15977
|
+
/** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
|
|
15978
|
+
* matches every raw class that maps to it; any other name matches
|
|
15979
|
+
* exactly. */
|
|
15980
|
+
classes: array(string().min(1)).min(1),
|
|
15981
|
+
deviceIds: array(number().int().nonnegative()).min(1),
|
|
15982
|
+
/** The track must have visited at least one of these zones. */
|
|
15983
|
+
zones: array(string().min(1)).min(1).optional(),
|
|
15984
|
+
/** Best-so-far confidence the track must reach. */
|
|
15985
|
+
minScore: number().min(0).max(1).optional()
|
|
15986
|
+
}),
|
|
15987
|
+
object({
|
|
15988
|
+
kind: literal("stationary"),
|
|
15989
|
+
deviceIds: array(number().int().nonnegative()).min(1),
|
|
15990
|
+
/** Class names; a macro class matches like the detection trigger. */
|
|
15991
|
+
classes: array(string().min(1)).min(1).optional(),
|
|
15992
|
+
/** The parked object must be in at least one of these zones. */
|
|
15993
|
+
zones: array(string().min(1)).min(1).optional(),
|
|
15994
|
+
/** `appeared`: it became parked. `departed`: the registry retired it.
|
|
15995
|
+
* The vocabulary of `PipelineAnalyticsStationaryChanged`. */
|
|
15996
|
+
phase: _enum(["appeared", "departed"])
|
|
15997
|
+
}),
|
|
15998
|
+
object({
|
|
15999
|
+
kind: literal("interval"),
|
|
16000
|
+
minutes: number().int().min(1).max(1440)
|
|
16001
|
+
})
|
|
15770
16002
|
]);
|
|
15771
16003
|
/**
|
|
15772
16004
|
* One action step.
|
|
@@ -15786,28 +16018,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
|
|
|
15786
16018
|
* is called. The runner still receives a number and is untouched; the
|
|
15787
16019
|
* resolution is the recipe's job, not the runner's.
|
|
15788
16020
|
*/
|
|
16021
|
+
var AutomationWaitStepSchema = object({
|
|
16022
|
+
kind: literal("wait"),
|
|
16023
|
+
seconds: number().min(0).max(300)
|
|
16024
|
+
});
|
|
16025
|
+
var AutomationCapStepSchema = object({
|
|
16026
|
+
kind: literal("cap"),
|
|
16027
|
+
/**
|
|
16028
|
+
* One device, several same-family devices (locks / climate family / …),
|
|
16029
|
+
* or `{ $var }` for the device that triggered the run. An array is
|
|
16030
|
+
* fan-out at codegen — each id gets the same cap.method call.
|
|
16031
|
+
*/
|
|
16032
|
+
deviceId: union([
|
|
16033
|
+
number().int(),
|
|
16034
|
+
array(number().int()).min(1),
|
|
16035
|
+
object({ $var: string().min(1) })
|
|
16036
|
+
]),
|
|
16037
|
+
cap: string().min(1),
|
|
16038
|
+
method: string().min(1),
|
|
16039
|
+
/** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
|
|
16040
|
+
* SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
|
|
16041
|
+
* the expression leaf. */
|
|
16042
|
+
args: record(string(), unknown()).optional()
|
|
16043
|
+
});
|
|
16044
|
+
/**
|
|
16045
|
+
* The steps an internal Action may contain: cap and wait, and nothing that can
|
|
16046
|
+
* call back into an Action — so an Action can never reach itself (no cycles).
|
|
16047
|
+
*/
|
|
16048
|
+
var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
|
|
15789
16049
|
var AutomationActionSchema = discriminatedUnion("kind", [
|
|
16050
|
+
AutomationWaitStepSchema,
|
|
16051
|
+
AutomationCapStepSchema,
|
|
15790
16052
|
object({
|
|
15791
|
-
kind: literal("
|
|
15792
|
-
|
|
15793
|
-
|
|
15794
|
-
|
|
15795
|
-
|
|
15796
|
-
|
|
15797
|
-
|
|
15798
|
-
|
|
15799
|
-
|
|
15800
|
-
*/
|
|
15801
|
-
deviceId: union([
|
|
15802
|
-
number().int(),
|
|
15803
|
-
array(number().int()).min(1),
|
|
15804
|
-
object({ $var: string().min(1) })
|
|
15805
|
-
]),
|
|
15806
|
-
cap: string().min(1),
|
|
15807
|
-
method: string().min(1),
|
|
15808
|
-
/** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
|
|
15809
|
-
* evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
|
|
15810
|
-
args: record(string(), unknown()).optional()
|
|
16053
|
+
kind: literal("action"),
|
|
16054
|
+
/** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
|
|
16055
|
+
actionId: string().min(1),
|
|
16056
|
+
/** Values for the action's declared variables; the others take their default. */
|
|
16057
|
+
variables: record(string(), union([
|
|
16058
|
+
string(),
|
|
16059
|
+
number(),
|
|
16060
|
+
boolean()
|
|
16061
|
+
])).optional()
|
|
15811
16062
|
}),
|
|
15812
16063
|
object({
|
|
15813
16064
|
kind: literal("code"),
|
|
@@ -15816,10 +16067,778 @@ var AutomationActionSchema = discriminatedUnion("kind", [
|
|
|
15816
16067
|
code: string().min(1).max(2e4)
|
|
15817
16068
|
})
|
|
15818
16069
|
]);
|
|
16070
|
+
/**
|
|
16071
|
+
* How a trigger that arrives while the automation is busy (or cooling down) is
|
|
16072
|
+
* handled. One of the automation's execution modes, never a property of its
|
|
16073
|
+
* actions. Absent means `single`.
|
|
16074
|
+
*
|
|
16075
|
+
* - `single` — drop the trigger while a run is in progress (traced + logged).
|
|
16076
|
+
* - `restart` — abort the run in progress (at its next step boundary), start fresh.
|
|
16077
|
+
* - `queued` — queue up to `max` triggers, drop the rest (traced).
|
|
16078
|
+
* - `parallel` — up to `max` runs at once, drop the rest (traced).
|
|
16079
|
+
* - `cooldown` — `single`, and no new run until `minutes` after the last run
|
|
16080
|
+
* STARTED; persisted across a restart. A manual trigger bypasses only this
|
|
16081
|
+
* wait, never the single/queued limits.
|
|
16082
|
+
*/
|
|
16083
|
+
var AutomationRunModeSchema = discriminatedUnion("mode", [
|
|
16084
|
+
object({ mode: literal("single") }),
|
|
16085
|
+
object({ mode: literal("restart") }),
|
|
16086
|
+
object({
|
|
16087
|
+
mode: literal("queued"),
|
|
16088
|
+
max: number().int().min(1).max(10)
|
|
16089
|
+
}),
|
|
16090
|
+
object({
|
|
16091
|
+
mode: literal("parallel"),
|
|
16092
|
+
max: number().int().min(1).max(10)
|
|
16093
|
+
}),
|
|
16094
|
+
object({
|
|
16095
|
+
mode: literal("cooldown"),
|
|
16096
|
+
minutes: number().int().min(1).max(1440)
|
|
16097
|
+
})
|
|
16098
|
+
]);
|
|
15819
16099
|
var AutomationRecipeSchema = object({
|
|
15820
16100
|
triggers: array(AutomationTriggerSchema),
|
|
15821
16101
|
conditions: AutomationConditionSchema.optional(),
|
|
15822
|
-
actions: array(AutomationActionSchema)
|
|
16102
|
+
actions: array(AutomationActionSchema),
|
|
16103
|
+
runMode: AutomationRunModeSchema.optional(),
|
|
16104
|
+
/** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
|
|
16105
|
+
keepTraces: number().int().min(1).max(100).optional()
|
|
16106
|
+
});
|
|
16107
|
+
new Set([
|
|
16108
|
+
{
|
|
16109
|
+
id: "person",
|
|
16110
|
+
name: "Person"
|
|
16111
|
+
},
|
|
16112
|
+
{
|
|
16113
|
+
id: "vehicle",
|
|
16114
|
+
name: "Vehicle"
|
|
16115
|
+
},
|
|
16116
|
+
{
|
|
16117
|
+
id: "animal",
|
|
16118
|
+
name: "Animal"
|
|
16119
|
+
},
|
|
16120
|
+
{
|
|
16121
|
+
id: "package",
|
|
16122
|
+
name: "Package"
|
|
16123
|
+
}
|
|
16124
|
+
].map((l) => l.id));
|
|
16125
|
+
var COCO_TO_MACRO = {
|
|
16126
|
+
mapping: {
|
|
16127
|
+
person: "person",
|
|
16128
|
+
bicycle: "vehicle",
|
|
16129
|
+
car: "vehicle",
|
|
16130
|
+
motorcycle: "vehicle",
|
|
16131
|
+
airplane: "vehicle",
|
|
16132
|
+
bus: "vehicle",
|
|
16133
|
+
train: "vehicle",
|
|
16134
|
+
truck: "vehicle",
|
|
16135
|
+
boat: "vehicle",
|
|
16136
|
+
bird: "animal",
|
|
16137
|
+
cat: "animal",
|
|
16138
|
+
dog: "animal",
|
|
16139
|
+
horse: "animal",
|
|
16140
|
+
sheep: "animal",
|
|
16141
|
+
cow: "animal",
|
|
16142
|
+
elephant: "animal",
|
|
16143
|
+
bear: "animal",
|
|
16144
|
+
zebra: "animal",
|
|
16145
|
+
giraffe: "animal",
|
|
16146
|
+
suitcase: "package",
|
|
16147
|
+
backpack: "package",
|
|
16148
|
+
handbag: "package"
|
|
16149
|
+
},
|
|
16150
|
+
preserveOriginal: false
|
|
16151
|
+
};
|
|
16152
|
+
new Set(Object.values(COCO_TO_MACRO.mapping));
|
|
16153
|
+
/**
|
|
16154
|
+
* Run traces — what an automation (or, later, an Action run) DID, node by node,
|
|
16155
|
+
* so the editor can paint every block green or red with its reason.
|
|
16156
|
+
*
|
|
16157
|
+
* A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
|
|
16158
|
+
* every condition node (containers and leaves, including the ones a
|
|
16159
|
+
* short-circuit never reached), the run-mode verdict and every action step —
|
|
16160
|
+
* each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
|
|
16161
|
+
* for an Action run). Skipped
|
|
16162
|
+
* evaluations are traced too, and identical consecutive skips collapse into a
|
|
16163
|
+
* repeat count so a trigger that fails every 5 minutes cannot flush real runs.
|
|
16164
|
+
*
|
|
16165
|
+
* {@link AutomationStepTraceSchema} is deliberately free of automation
|
|
16166
|
+
* vocabulary so an Action run records the same step shape.
|
|
16167
|
+
*/
|
|
16168
|
+
/** A value a trace may show: JSON primitives and short lists, nothing deeper. */
|
|
16169
|
+
var TraceValueSchema = union([
|
|
16170
|
+
string(),
|
|
16171
|
+
number(),
|
|
16172
|
+
boolean(),
|
|
16173
|
+
_null(),
|
|
16174
|
+
array(union([string(), number()]))
|
|
16175
|
+
]);
|
|
16176
|
+
var AutomationRunOutcomeSchema = _enum([
|
|
16177
|
+
"ran",
|
|
16178
|
+
"skipped-trigger",
|
|
16179
|
+
"skipped-conditions",
|
|
16180
|
+
"skipped-cooldown",
|
|
16181
|
+
"skipped-overlap",
|
|
16182
|
+
"failed",
|
|
16183
|
+
"aborted"
|
|
16184
|
+
]);
|
|
16185
|
+
/** `not-evaluated` = a short-circuit never reached the node. */
|
|
16186
|
+
var TraceNodeOutcomeSchema = _enum([
|
|
16187
|
+
"pass",
|
|
16188
|
+
"fail",
|
|
16189
|
+
"not-evaluated"
|
|
16190
|
+
]);
|
|
16191
|
+
var AutomationTriggerTraceSchema = object({
|
|
16192
|
+
kind: string().min(1),
|
|
16193
|
+
outcome: _enum(["pass", "fail"]),
|
|
16194
|
+
/** Why an event was rejected ("class person not in [dog]") or what fired. */
|
|
16195
|
+
reason: string(),
|
|
16196
|
+
/** deviceId, className, trackId, score … — only what the trigger exposes. */
|
|
16197
|
+
vars: record(string(), TraceValueSchema)
|
|
16198
|
+
});
|
|
16199
|
+
var AutomationConditionTraceNodeSchema = object({
|
|
16200
|
+
/** `conditions` for the root, `conditions.<i>` for its i-th child, … */
|
|
16201
|
+
path: string().min(1),
|
|
16202
|
+
kind: _enum([
|
|
16203
|
+
"all",
|
|
16204
|
+
"any",
|
|
16205
|
+
"not",
|
|
16206
|
+
"condition",
|
|
16207
|
+
"expression",
|
|
16208
|
+
"stationary-present"
|
|
16209
|
+
]),
|
|
16210
|
+
outcome: TraceNodeOutcomeSchema,
|
|
16211
|
+
reason: string(),
|
|
16212
|
+
deviceId: number().int().optional(),
|
|
16213
|
+
cap: string().optional(),
|
|
16214
|
+
fieldPath: string().optional(),
|
|
16215
|
+
operator: string().optional(),
|
|
16216
|
+
expected: TraceValueSchema.optional(),
|
|
16217
|
+
/** What the mirror held; `null` when it held nothing (unknown). */
|
|
16218
|
+
observed: TraceValueSchema.optional()
|
|
16219
|
+
});
|
|
16220
|
+
var AutomationRunVerdictSchema = object({
|
|
16221
|
+
mode: AutomationRunModeSchema,
|
|
16222
|
+
decision: _enum([
|
|
16223
|
+
"run",
|
|
16224
|
+
"queued",
|
|
16225
|
+
"restart",
|
|
16226
|
+
"drop",
|
|
16227
|
+
"cooldown",
|
|
16228
|
+
"bypass"
|
|
16229
|
+
]),
|
|
16230
|
+
reason: string()
|
|
16231
|
+
});
|
|
16232
|
+
/** One executed (or not-run) step — shared by automations and Action runs. */
|
|
16233
|
+
var AutomationStepTraceSchema = object({
|
|
16234
|
+
/** `actions.<i>` */
|
|
16235
|
+
path: string().min(1),
|
|
16236
|
+
kind: string().min(1),
|
|
16237
|
+
cap: string().optional(),
|
|
16238
|
+
method: string().optional(),
|
|
16239
|
+
deviceId: number().int().optional(),
|
|
16240
|
+
startedAt: number().optional(),
|
|
16241
|
+
endedAt: number().optional(),
|
|
16242
|
+
outcome: _enum([
|
|
16243
|
+
"ok",
|
|
16244
|
+
"error",
|
|
16245
|
+
"not-run"
|
|
16246
|
+
]),
|
|
16247
|
+
message: string().optional()
|
|
16248
|
+
});
|
|
16249
|
+
var AutomationRunTraceSchema = object({
|
|
16250
|
+
runId: string().min(1),
|
|
16251
|
+
startedAt: number(),
|
|
16252
|
+
endedAt: number(),
|
|
16253
|
+
trigger: AutomationTriggerTraceSchema,
|
|
16254
|
+
conditions: array(AutomationConditionTraceNodeSchema),
|
|
16255
|
+
verdict: AutomationRunVerdictSchema.optional(),
|
|
16256
|
+
steps: array(AutomationStepTraceSchema),
|
|
16257
|
+
outcome: AutomationRunOutcomeSchema,
|
|
16258
|
+
/** How many identical consecutive skips this trace stands for (>= 1). */
|
|
16259
|
+
repeat: number().int().min(1),
|
|
16260
|
+
/** When the latest of those repeats happened. */
|
|
16261
|
+
lastAt: number()
|
|
16262
|
+
});
|
|
16263
|
+
/**
|
|
16264
|
+
* What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
|
|
16265
|
+
* `action:<actionId>`): the cooldown stamp and the trace ring.
|
|
16266
|
+
*/
|
|
16267
|
+
var AutomationStateDocSchema = object({
|
|
16268
|
+
version: literal(1),
|
|
16269
|
+
lastRunStartedAt: number().nullable(),
|
|
16270
|
+
traces: array(AutomationRunTraceSchema)
|
|
16271
|
+
});
|
|
16272
|
+
/**
|
|
16273
|
+
* Actions — named, runnable things an operator (or an automation) can start,
|
|
16274
|
+
* declared as LIST ENTRIES, never as devices.
|
|
16275
|
+
*
|
|
16276
|
+
* An entry is either **internal** (a short list of cap/wait steps kept in the
|
|
16277
|
+
* hub's `actions` record kind) or declared by an addon through the
|
|
16278
|
+
* `action-source` collection (a Home Assistant script, a scene …). The one
|
|
16279
|
+
* surface the UI and automations talk to is the `actions` cap; it keeps no
|
|
16280
|
+
* catalog of its own (D3) — every `list` asks the providers live.
|
|
16281
|
+
*
|
|
16282
|
+
* This file is the data half: the entry schema, the variables an entry may
|
|
16283
|
+
* declare, and the pure resolution of the values a run was given. It holds no
|
|
16284
|
+
* runtime.
|
|
16285
|
+
*/
|
|
16286
|
+
/** What a variable's value is. `select` takes one of `options`. */
|
|
16287
|
+
var ActionVariableTypeSchema = _enum([
|
|
16288
|
+
"string",
|
|
16289
|
+
"number",
|
|
16290
|
+
"boolean",
|
|
16291
|
+
"select"
|
|
16292
|
+
]);
|
|
16293
|
+
var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
16294
|
+
var ActionVariableValueSchema = union([
|
|
16295
|
+
string(),
|
|
16296
|
+
number(),
|
|
16297
|
+
boolean()
|
|
16298
|
+
]);
|
|
16299
|
+
/**
|
|
16300
|
+
* One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
|
|
16301
|
+
* value) or `{{vars.name}}` (inside a string) in their args.
|
|
16302
|
+
*/
|
|
16303
|
+
var ActionVariableSchema = object({
|
|
16304
|
+
name: string().regex(ACTION_VARIABLE_NAME_RE),
|
|
16305
|
+
label: string().min(1).max(120).optional(),
|
|
16306
|
+
type: ActionVariableTypeSchema,
|
|
16307
|
+
required: boolean().optional(),
|
|
16308
|
+
default: ActionVariableValueSchema.optional(),
|
|
16309
|
+
/** The allowed values of a `select`. */
|
|
16310
|
+
options: array(string().min(1)).min(1).optional()
|
|
16311
|
+
}).superRefine((v, ctx) => {
|
|
16312
|
+
if (v.type === "select" && v.options === void 0) ctx.addIssue({
|
|
16313
|
+
code: "custom",
|
|
16314
|
+
message: "a select variable needs options",
|
|
16315
|
+
path: ["options"]
|
|
16316
|
+
});
|
|
16317
|
+
if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
|
|
16318
|
+
code: "custom",
|
|
16319
|
+
message: variableValueError(v, v.default) ?? "invalid default",
|
|
16320
|
+
path: ["default"]
|
|
16321
|
+
});
|
|
16322
|
+
});
|
|
16323
|
+
/** Why `value` is not a legal value for the variable, or null when it is. */
|
|
16324
|
+
function variableValueError(variable, value) {
|
|
16325
|
+
switch (variable.type) {
|
|
16326
|
+
case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
|
|
16327
|
+
case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
|
|
16328
|
+
case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
|
|
16329
|
+
case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
|
|
16330
|
+
}
|
|
16331
|
+
}
|
|
16332
|
+
var ActionSourceKindSchema = _enum(["internal", "addon"]);
|
|
16333
|
+
function isInternalActionId(actionId) {
|
|
16334
|
+
return actionId.startsWith("internal:") && actionId.length > 9;
|
|
16335
|
+
}
|
|
16336
|
+
/** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
|
|
16337
|
+
function addonIdOfActionId(actionId) {
|
|
16338
|
+
if (isInternalActionId(actionId)) return null;
|
|
16339
|
+
const at = actionId.indexOf(":");
|
|
16340
|
+
return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
|
|
16341
|
+
}
|
|
16342
|
+
var ActionStatusSchema = object({
|
|
16343
|
+
isRunning: boolean(),
|
|
16344
|
+
/** Ms epoch the latest run STARTED; null when it never ran. */
|
|
16345
|
+
lastRunAt: number().nullable(),
|
|
16346
|
+
/** The latest run's failure; null on success or when it never ran. */
|
|
16347
|
+
lastError: string().nullable()
|
|
16348
|
+
});
|
|
16349
|
+
var ActionEntrySchema = object({
|
|
16350
|
+
/** `internal:<uuid>` or `<addonId>:<localId>`. */
|
|
16351
|
+
id: string().min(3),
|
|
16352
|
+
name: string().min(1).max(120),
|
|
16353
|
+
/** The addon that declared it; `core-blocks` for an internal one. */
|
|
16354
|
+
addonId: string().min(1),
|
|
16355
|
+
source: ActionSourceKindSchema,
|
|
16356
|
+
/** An addon-declared entry is edited where it was declared. */
|
|
16357
|
+
readOnly: boolean(),
|
|
16358
|
+
/** Internal only: cap and wait steps. No action-in-action, so no cycles. */
|
|
16359
|
+
steps: array(ActionStepSchema).min(1).max(50).optional(),
|
|
16360
|
+
variables: array(ActionVariableSchema).max(20).optional(),
|
|
16361
|
+
status: ActionStatusSchema
|
|
16362
|
+
}).superRefine((entry, ctx) => {
|
|
16363
|
+
if (entry.source === "internal") {
|
|
16364
|
+
if (!isInternalActionId(entry.id)) ctx.addIssue({
|
|
16365
|
+
code: "custom",
|
|
16366
|
+
message: "an internal action id is internal:<uuid>",
|
|
16367
|
+
path: ["id"]
|
|
16368
|
+
});
|
|
16369
|
+
return;
|
|
16370
|
+
}
|
|
16371
|
+
if (entry.steps !== void 0) ctx.addIssue({
|
|
16372
|
+
code: "custom",
|
|
16373
|
+
message: "only an internal action carries steps",
|
|
16374
|
+
path: ["steps"]
|
|
16375
|
+
});
|
|
16376
|
+
if (!entry.readOnly) ctx.addIssue({
|
|
16377
|
+
code: "custom",
|
|
16378
|
+
message: "an addon action is read-only here",
|
|
16379
|
+
path: ["readOnly"]
|
|
16380
|
+
});
|
|
16381
|
+
if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
|
|
16382
|
+
code: "custom",
|
|
16383
|
+
message: "an addon action id is <addonId>:<localId>",
|
|
16384
|
+
path: ["id"]
|
|
16385
|
+
});
|
|
16386
|
+
});
|
|
16387
|
+
/** What an operator writes for an internal action. */
|
|
16388
|
+
var ActionInputSchema = object({
|
|
16389
|
+
name: string().min(1).max(120),
|
|
16390
|
+
steps: array(ActionStepSchema).min(1).max(50),
|
|
16391
|
+
variables: array(ActionVariableSchema).max(20).optional()
|
|
16392
|
+
});
|
|
16393
|
+
/** Who started a run. Absent = the operator pressed it. */
|
|
16394
|
+
var ActionRunOriginSchema = object({
|
|
16395
|
+
/** The automation block whose step started it. */
|
|
16396
|
+
blockId: string().min(1).optional() });
|
|
16397
|
+
/** `started` = the caller did not ask to wait. */
|
|
16398
|
+
var ActionRunOutcomeSchema = union([AutomationRunOutcomeSchema, literal("started")]);
|
|
16399
|
+
var ActionRunResultSchema = object({
|
|
16400
|
+
runId: string().min(1),
|
|
16401
|
+
outcome: ActionRunOutcomeSchema,
|
|
16402
|
+
/** Why it did not run, or what failed. */
|
|
16403
|
+
message: string().optional()
|
|
16404
|
+
});
|
|
16405
|
+
_enum([
|
|
16406
|
+
"not-found",
|
|
16407
|
+
"read-only",
|
|
16408
|
+
"invalid-variables",
|
|
16409
|
+
"invalid-steps",
|
|
16410
|
+
"not-linked",
|
|
16411
|
+
"busy"
|
|
16412
|
+
]);
|
|
16413
|
+
object({
|
|
16414
|
+
actionId: string(),
|
|
16415
|
+
runId: string(),
|
|
16416
|
+
isRunning: boolean(),
|
|
16417
|
+
/** Set when the run ended. */
|
|
16418
|
+
outcome: AutomationRunOutcomeSchema.optional(),
|
|
16419
|
+
lastRunAt: number().nullable(),
|
|
16420
|
+
lastError: string().nullable()
|
|
16421
|
+
});
|
|
16422
|
+
/**
|
|
16423
|
+
* notification-output — canonical, capability-gated notification delivery.
|
|
16424
|
+
*
|
|
16425
|
+
* Apprise-derived model (see
|
|
16426
|
+
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
16427
|
+
* callers emit ONE canonical `Notification`; each provider declares a
|
|
16428
|
+
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
16429
|
+
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
16430
|
+
* message to what the kind supports — callers never special-case a service.
|
|
16431
|
+
*
|
|
16432
|
+
* DESIGN DECISIONS (locked):
|
|
16433
|
+
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
16434
|
+
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
16435
|
+
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
16436
|
+
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
16437
|
+
* alternative would fork the UI per addon and cannot host the
|
|
16438
|
+
* discovery→adopt flow.
|
|
16439
|
+
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
16440
|
+
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
16441
|
+
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
16442
|
+
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
16443
|
+
* `addonId` the generated collection router extracts from the call input.
|
|
16444
|
+
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
16445
|
+
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
16446
|
+
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
16447
|
+
* base64 fallback needed.
|
|
16448
|
+
*
|
|
16449
|
+
* TODO (deferred, closed-set change — separate decision): add
|
|
16450
|
+
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
16451
|
+
* admin "Integrations" page.
|
|
16452
|
+
*/
|
|
16453
|
+
/**
|
|
16454
|
+
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
16455
|
+
* adapter picks what it supports and the degrade engine filters the rest.
|
|
16456
|
+
*/
|
|
16457
|
+
var AttachmentMediaTypeSchema = _enum([
|
|
16458
|
+
"image",
|
|
16459
|
+
"video",
|
|
16460
|
+
"gif",
|
|
16461
|
+
"audio",
|
|
16462
|
+
"icon"
|
|
16463
|
+
]);
|
|
16464
|
+
/**
|
|
16465
|
+
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
16466
|
+
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
16467
|
+
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
16468
|
+
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
16469
|
+
*/
|
|
16470
|
+
var AttachmentSchema = object({
|
|
16471
|
+
mediaType: AttachmentMediaTypeSchema,
|
|
16472
|
+
url: string().optional(),
|
|
16473
|
+
bytes: _instanceof(Uint8Array).optional(),
|
|
16474
|
+
mime: string().optional(),
|
|
16475
|
+
name: string().optional()
|
|
16476
|
+
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
16477
|
+
var NotificationFormatSchema = _enum([
|
|
16478
|
+
"text",
|
|
16479
|
+
"markdown",
|
|
16480
|
+
"html"
|
|
16481
|
+
]);
|
|
16482
|
+
/**
|
|
16483
|
+
* The CLOSED icon vocabulary an action button may use.
|
|
16484
|
+
*
|
|
16485
|
+
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
16486
|
+
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
16487
|
+
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
16488
|
+
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
16489
|
+
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
16490
|
+
*
|
|
16491
|
+
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
16492
|
+
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
16493
|
+
* differently.
|
|
16494
|
+
*
|
|
16495
|
+
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
16496
|
+
*
|
|
16497
|
+
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
16498
|
+
* the whole set onto its own renderer's vocabulary through a
|
|
16499
|
+
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
16500
|
+
* fallback, so adding a member here fails every adapter's build until someone
|
|
16501
|
+
* decides its glyph, which is the only place that decision can be made
|
|
16502
|
+
* honestly.
|
|
16503
|
+
*
|
|
16504
|
+
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
16505
|
+
* `disarm` straight through; iOS feeds that string to
|
|
16506
|
+
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
16507
|
+
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
16508
|
+
* mapping, and "the field is documented" is not "the value renders".
|
|
16509
|
+
*
|
|
16510
|
+
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
16511
|
+
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
16512
|
+
* so an addon that emits a token the running hub does not know does not lose an
|
|
16513
|
+
* icon — its whole `send` fails Zod validation and the notification never
|
|
16514
|
+
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
16515
|
+
*/
|
|
16516
|
+
var NotificationActionIconSchema = _enum([
|
|
16517
|
+
"acknowledge",
|
|
16518
|
+
"dismiss",
|
|
16519
|
+
"silence",
|
|
16520
|
+
"snooze",
|
|
16521
|
+
"view",
|
|
16522
|
+
"play",
|
|
16523
|
+
"open",
|
|
16524
|
+
"close",
|
|
16525
|
+
"lock",
|
|
16526
|
+
"unlock",
|
|
16527
|
+
"arm",
|
|
16528
|
+
"arm-home",
|
|
16529
|
+
"arm-away",
|
|
16530
|
+
"arm-night",
|
|
16531
|
+
"disarm",
|
|
16532
|
+
"light",
|
|
16533
|
+
"alert",
|
|
16534
|
+
"camera"
|
|
16535
|
+
]);
|
|
16536
|
+
/** A single tap-through action button. */
|
|
16537
|
+
var NotificationActionSchema = object({
|
|
16538
|
+
id: string(),
|
|
16539
|
+
label: string(),
|
|
16540
|
+
url: string().optional(),
|
|
16541
|
+
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
16542
|
+
icon: NotificationActionIconSchema.optional(),
|
|
16543
|
+
/**
|
|
16544
|
+
* Renders in a warning style where the notifier supports it.
|
|
16545
|
+
*
|
|
16546
|
+
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
16547
|
+
* else — see `notification-center/action-token.ts` for what that does and
|
|
16548
|
+
* does not buy.
|
|
16549
|
+
*/
|
|
16550
|
+
destructive: boolean().optional(),
|
|
16551
|
+
/**
|
|
16552
|
+
* How the tap should REACH the url.
|
|
16553
|
+
*
|
|
16554
|
+
* `navigate` (absent, and every button authored before this field) opens it:
|
|
16555
|
+
* the phone leaves the notification and shows whatever the callback returns.
|
|
16556
|
+
* That is right for a button whose answer the operator wants to read.
|
|
16557
|
+
*
|
|
16558
|
+
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
16559
|
+
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
16560
|
+
* an answer to the notification, and being thrown into a browser tab to
|
|
16561
|
+
* confirm it costs more attention than the notification did. A backend that
|
|
16562
|
+
* cannot do a background call renders it as an ordinary link (the adapters
|
|
16563
|
+
* fall back rather than dropping the button), so this is a preference, never
|
|
16564
|
+
* a requirement.
|
|
16565
|
+
*/
|
|
16566
|
+
mode: _enum(["navigate", "background"]).optional()
|
|
16567
|
+
});
|
|
16568
|
+
/** A delivery parameter value: what a notifier declared it takes. */
|
|
16569
|
+
var DeliveryParamValueSchema = union([
|
|
16570
|
+
string(),
|
|
16571
|
+
number(),
|
|
16572
|
+
boolean()
|
|
16573
|
+
]);
|
|
16574
|
+
/**
|
|
16575
|
+
* One extra delivery parameter a notifier KIND declares (D938). A rule that
|
|
16576
|
+
* addresses a target of that kind may set it; a kind that declares nothing is
|
|
16577
|
+
* never handed one. The admin UI derives its control from this descriptor —
|
|
16578
|
+
* no editor knows a service by name.
|
|
16579
|
+
*
|
|
16580
|
+
* Optional fields are `.optional()`, never `.default()` (a Zod default does not
|
|
16581
|
+
* run on the addon cap path).
|
|
16582
|
+
*/
|
|
16583
|
+
var DeliveryParamSchema = object({
|
|
16584
|
+
key: string().min(1),
|
|
16585
|
+
label: string(),
|
|
16586
|
+
/** i18n key of the label, resolved by the declaring addon's namespace. */
|
|
16587
|
+
labelKey: string().optional(),
|
|
16588
|
+
type: _enum([
|
|
16589
|
+
"enum",
|
|
16590
|
+
"number",
|
|
16591
|
+
"boolean",
|
|
16592
|
+
"string"
|
|
16593
|
+
]),
|
|
16594
|
+
/** `enum` only: the closed set of accepted values. */
|
|
16595
|
+
options: array(object({
|
|
16596
|
+
value: string(),
|
|
16597
|
+
label: string()
|
|
16598
|
+
})).optional(),
|
|
16599
|
+
/** `number` only. */
|
|
16600
|
+
min: number().optional(),
|
|
16601
|
+
max: number().optional(),
|
|
16602
|
+
/** What the notifier does when the rule sets nothing; shown as the placeholder. */
|
|
16603
|
+
default: DeliveryParamValueSchema.optional()
|
|
16604
|
+
});
|
|
16605
|
+
/**
|
|
16606
|
+
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
16607
|
+
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
16608
|
+
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
16609
|
+
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
16610
|
+
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
16611
|
+
* `priority` for that one target.
|
|
16612
|
+
*/
|
|
16613
|
+
var NotificationSchema = object({
|
|
16614
|
+
body: string(),
|
|
16615
|
+
title: string().optional(),
|
|
16616
|
+
format: NotificationFormatSchema.default("text"),
|
|
16617
|
+
priority: number().int().min(1).max(5).default(3),
|
|
16618
|
+
level: string().optional(),
|
|
16619
|
+
attachments: array(AttachmentSchema).optional(),
|
|
16620
|
+
clickUrl: string().optional(),
|
|
16621
|
+
actions: array(NotificationActionSchema).optional(),
|
|
16622
|
+
sound: string().optional(),
|
|
16623
|
+
ttl: number().optional(),
|
|
16624
|
+
tag: string().optional(),
|
|
16625
|
+
deviceId: number().optional(),
|
|
16626
|
+
eventId: string().optional(),
|
|
16627
|
+
metadata: record(string(), unknown()).optional(),
|
|
16628
|
+
/**
|
|
16629
|
+
* Values for the parameters the target's kind DECLARES in
|
|
16630
|
+
* {@link TargetKindSchema} `deliveryParams`. Already validated against the
|
|
16631
|
+
* declaration by the sender; a notifier reads only the keys it declared.
|
|
16632
|
+
*/
|
|
16633
|
+
delivery: record(string(), DeliveryParamValueSchema).optional()
|
|
16634
|
+
});
|
|
16635
|
+
/** One declared native severity/priority level for a kind. */
|
|
16636
|
+
var TargetKindLevelSchema = object({
|
|
16637
|
+
id: string(),
|
|
16638
|
+
label: string(),
|
|
16639
|
+
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
16640
|
+
ordinal: number().int().min(1).max(5).nullable(),
|
|
16641
|
+
flags: object({
|
|
16642
|
+
critical: boolean().optional(),
|
|
16643
|
+
silent: boolean().optional(),
|
|
16644
|
+
noPush: boolean().optional()
|
|
16645
|
+
}).optional(),
|
|
16646
|
+
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
16647
|
+
requires: array(string()).optional(),
|
|
16648
|
+
description: string().optional()
|
|
16649
|
+
});
|
|
16650
|
+
/** The full capability block consulted before dispatch. */
|
|
16651
|
+
var TargetKindCapsSchema = object({
|
|
16652
|
+
attachments: object({
|
|
16653
|
+
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
16654
|
+
mode: _enum([
|
|
16655
|
+
"url",
|
|
16656
|
+
"bytes",
|
|
16657
|
+
"both"
|
|
16658
|
+
]),
|
|
16659
|
+
max: number().int().nonnegative(),
|
|
16660
|
+
maxBytes: number().int().positive().optional()
|
|
16661
|
+
}),
|
|
16662
|
+
/** Max action buttons (0 = none). */
|
|
16663
|
+
actions: number().int().nonnegative(),
|
|
16664
|
+
/**
|
|
16665
|
+
* Whether this kind renders a per-action ICON.
|
|
16666
|
+
*
|
|
16667
|
+
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
16668
|
+
* run on the addon cap path — three production failures in one day taught
|
|
16669
|
+
* this repo that once. Absent is read as false by the degrade engine, which
|
|
16670
|
+
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
16671
|
+
* assumed and dropped costs the operator's trust in the field.
|
|
16672
|
+
*/
|
|
16673
|
+
actionIcons: boolean().optional(),
|
|
16674
|
+
levels: array(TargetKindLevelSchema),
|
|
16675
|
+
format: array(NotificationFormatSchema),
|
|
16676
|
+
clickUrl: boolean(),
|
|
16677
|
+
sound: boolean(),
|
|
16678
|
+
ttl: boolean(),
|
|
16679
|
+
bodyMaxLen: number().int().positive()
|
|
16680
|
+
});
|
|
16681
|
+
/**
|
|
16682
|
+
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
16683
|
+
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
16684
|
+
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
16685
|
+
* the union is large and not meant for runtime validation here; the exported
|
|
16686
|
+
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
16687
|
+
*/
|
|
16688
|
+
var ConfigSchemaPassthrough$3 = unknown();
|
|
16689
|
+
var TargetKindSchema = object({
|
|
16690
|
+
kind: string(),
|
|
16691
|
+
label: string(),
|
|
16692
|
+
icon: string(),
|
|
16693
|
+
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
16694
|
+
addonId: string(),
|
|
16695
|
+
/**
|
|
16696
|
+
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
16697
|
+
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
16698
|
+
* when the addon bundles no icon for that kind — the client then falls back
|
|
16699
|
+
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
16700
|
+
*
|
|
16701
|
+
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
16702
|
+
* client, and a native client joins it onto its own hub base.
|
|
16703
|
+
*
|
|
16704
|
+
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
16705
|
+
* field that survived only because the runtime cap-router forwards provider
|
|
16706
|
+
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
16707
|
+
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
16708
|
+
* broken silently the moment output validation was tightened anywhere.
|
|
16709
|
+
*/
|
|
16710
|
+
iconUrl: string().optional(),
|
|
16711
|
+
/**
|
|
16712
|
+
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
16713
|
+
*
|
|
16714
|
+
* The server knows this and therefore says it, because the client cannot
|
|
16715
|
+
* safely guess: a React-Native client renders SVG and raster through two
|
|
16716
|
+
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
16717
|
+
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
16718
|
+
* placeholder glyph for every vector icon while the web build looked fine.
|
|
16719
|
+
*
|
|
16720
|
+
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
16721
|
+
* not been updated — a client that cannot determine the type should prefer
|
|
16722
|
+
* its raster path, which is the safe default for an unknown image.
|
|
16723
|
+
*/
|
|
16724
|
+
iconMediaType: string().optional(),
|
|
16725
|
+
configSchema: ConfigSchemaPassthrough$3,
|
|
16726
|
+
/**
|
|
16727
|
+
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
16728
|
+
* base URL, instance, chat, recipient). A save that changes any of them
|
|
16729
|
+
* while leaving a secret redacted is refused by the provider (D634), so an
|
|
16730
|
+
* editor uses this to ask for the secret on exactly those edits instead of
|
|
16731
|
+
* on every edit.
|
|
16732
|
+
*
|
|
16733
|
+
* Optional: absent from a provider that holds no secret (the Home Assistant
|
|
16734
|
+
* kinds) and from a provider older than this field — an editor that finds
|
|
16735
|
+
* it absent must assume ANY edit may need the secret.
|
|
16736
|
+
*/
|
|
16737
|
+
destinationKeys: array(string()).optional(),
|
|
16738
|
+
supportsDiscovery: boolean(),
|
|
16739
|
+
/**
|
|
16740
|
+
* Extra delivery parameters a rule may set for a target of this kind (D938).
|
|
16741
|
+
* Absent = none; the rule editor then offers nothing.
|
|
16742
|
+
*/
|
|
16743
|
+
deliveryParams: array(DeliveryParamSchema).optional(),
|
|
16744
|
+
caps: TargetKindCapsSchema
|
|
16745
|
+
});
|
|
16746
|
+
/**
|
|
16747
|
+
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
16748
|
+
* (return a presence marker only) when serving `listTargets` — never
|
|
16749
|
+
* round-trip a stored secret to the UI.
|
|
16750
|
+
*/
|
|
16751
|
+
var TargetSchema = object({
|
|
16752
|
+
id: string(),
|
|
16753
|
+
name: string(),
|
|
16754
|
+
kind: string(),
|
|
16755
|
+
addonId: string(),
|
|
16756
|
+
enabled: boolean(),
|
|
16757
|
+
config: record(string(), unknown())
|
|
16758
|
+
});
|
|
16759
|
+
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
16760
|
+
var DiscoveredTargetSchema = object({
|
|
16761
|
+
kind: string(),
|
|
16762
|
+
suggestedName: string(),
|
|
16763
|
+
config: record(string(), unknown())
|
|
16764
|
+
});
|
|
16765
|
+
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
16766
|
+
var RenderedAsSchema = object({
|
|
16767
|
+
level: string(),
|
|
16768
|
+
format: NotificationFormatSchema,
|
|
16769
|
+
attachmentsSent: number().int().nonnegative(),
|
|
16770
|
+
actionsSent: number().int().nonnegative(),
|
|
16771
|
+
truncated: boolean(),
|
|
16772
|
+
dropped: array(string())
|
|
16773
|
+
});
|
|
16774
|
+
var SendResultSchema = object({
|
|
16775
|
+
success: boolean(),
|
|
16776
|
+
error: string().optional(),
|
|
16777
|
+
renderedAs: RenderedAsSchema.optional()
|
|
16778
|
+
});
|
|
16779
|
+
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
16780
|
+
var TestResultSchema = SendResultSchema;
|
|
16781
|
+
/**
|
|
16782
|
+
* Pre-save credential probe against a partial (unsaved) target config.
|
|
16783
|
+
* `resolvedUrl` never includes secrets (token stripped from path).
|
|
16784
|
+
*/
|
|
16785
|
+
var ProbeTargetConfigResultSchema = object({
|
|
16786
|
+
ok: boolean(),
|
|
16787
|
+
resolvedUrl: string(),
|
|
16788
|
+
httpStatus: number().int().optional(),
|
|
16789
|
+
stateInstance: string().optional(),
|
|
16790
|
+
error: string().optional()
|
|
16791
|
+
});
|
|
16792
|
+
method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema), { auth: "admin" }), method(object({ targetId: string() }), TargetSchema, { auth: "admin" }), method(object({
|
|
16793
|
+
kind: string(),
|
|
16794
|
+
config: record(string(), unknown()).optional(),
|
|
16795
|
+
/**
|
|
16796
|
+
* When editing / duplicating, the blank password field never round-trips
|
|
16797
|
+
* the stored token. Pass the source target id so the provider can restore
|
|
16798
|
+
* secrets server-side before dialling (same merge as upsert).
|
|
16799
|
+
*/
|
|
16800
|
+
targetId: string().optional()
|
|
16801
|
+
}), array(DiscoveredTargetSchema), { auth: "admin" }), method(object({
|
|
16802
|
+
kind: string(),
|
|
16803
|
+
config: record(string(), unknown()),
|
|
16804
|
+
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
16805
|
+
targetId: string().optional()
|
|
16806
|
+
}), ProbeTargetConfigResultSchema, {
|
|
16807
|
+
kind: "mutation",
|
|
16808
|
+
auth: "admin"
|
|
16809
|
+
}), method(object({
|
|
16810
|
+
targetId: string(),
|
|
16811
|
+
notification: NotificationSchema
|
|
16812
|
+
}), SendResultSchema, {
|
|
16813
|
+
kind: "mutation",
|
|
16814
|
+
auth: "admin"
|
|
16815
|
+
}), method(object({
|
|
16816
|
+
targetId: string(),
|
|
16817
|
+
sample: NotificationSchema.optional()
|
|
16818
|
+
}), TestResultSchema, {
|
|
16819
|
+
kind: "mutation",
|
|
16820
|
+
auth: "admin"
|
|
16821
|
+
}), method(object({
|
|
16822
|
+
target: TargetSchema,
|
|
16823
|
+
/**
|
|
16824
|
+
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
16825
|
+
* existing row. The UI never holds the stored token; blank / redacted
|
|
16826
|
+
* password fields are restored from this source (D634 still applies if
|
|
16827
|
+
* destinations diverge without a re-typed secret).
|
|
16828
|
+
*/
|
|
16829
|
+
cloneSecretsFrom: string().optional()
|
|
16830
|
+
}), TargetSchema, {
|
|
16831
|
+
kind: "mutation",
|
|
16832
|
+
auth: "admin"
|
|
16833
|
+
}), method(object({ targetId: string() }), _void(), {
|
|
16834
|
+
kind: "mutation",
|
|
16835
|
+
auth: "admin"
|
|
16836
|
+
}), method(object({
|
|
16837
|
+
targetId: string(),
|
|
16838
|
+
enabled: boolean()
|
|
16839
|
+
}), _void(), {
|
|
16840
|
+
kind: "mutation",
|
|
16841
|
+
auth: "admin"
|
|
15823
16842
|
});
|
|
15824
16843
|
/**
|
|
15825
16844
|
* `addon-pages` — system-scoped singleton aggregator cap. Public-facing
|
|
@@ -15853,52 +16872,6 @@ var AddonPageInfoSchema = object({
|
|
|
15853
16872
|
bundleUrl: string()
|
|
15854
16873
|
});
|
|
15855
16874
|
method(_void(), array(AddonPageInfoSchema).readonly());
|
|
15856
|
-
/**
|
|
15857
|
-
* `addon-pages-source` — collection cap exposing per-provider raw page
|
|
15858
|
-
* declarations. Every addon that contributes a UI page registers a
|
|
15859
|
-
* provider here. The hub-side singleton aggregator (`addon-pages` cap,
|
|
15860
|
-
* see `addon-pages.cap.ts`) walks this collection, stamps versioned
|
|
15861
|
-
* `bundleUrl` values, and returns the enriched `AddonPageInfo[]` list
|
|
15862
|
-
* that admin-ui consumes.
|
|
15863
|
-
*
|
|
15864
|
-
* The split exists because the public listing has a different output
|
|
15865
|
-
* shape than the per-provider raw declarations, and we want both ends
|
|
15866
|
-
* to flow through codegen instead of relying on a hand-written wrapper.
|
|
15867
|
-
*/
|
|
15868
|
-
var AddonPageDeclarationSchema = object({
|
|
15869
|
-
id: string(),
|
|
15870
|
-
label: string(),
|
|
15871
|
-
icon: string(),
|
|
15872
|
-
path: string(),
|
|
15873
|
-
/**
|
|
15874
|
-
* Module Federation remote name — must match the `name` field on the
|
|
15875
|
-
* page addon's `federation()` plugin config. Used by admin-ui's
|
|
15876
|
-
* `<AddonPageLoader>` to call `loadRemote('<remoteName>/page')`.
|
|
15877
|
-
* Conventionally `addon_<id>_page` (snake_case; MF names cannot
|
|
15878
|
-
* contain hyphens).
|
|
15879
|
-
*/
|
|
15880
|
-
remoteName: string(),
|
|
15881
|
-
/**
|
|
15882
|
-
* Bundle filename inside the addon's `dist/` dir served at
|
|
15883
|
-
* `/api/addon-pages/<addonId>/<bundle>`. With Module Federation this
|
|
15884
|
-
* is always `'remoteEntry.js'`; the value is kept on the metadata so
|
|
15885
|
-
* the static-file route can compute an mtime-based cache-buster URL
|
|
15886
|
-
* without a separate filesystem stat.
|
|
15887
|
-
*/
|
|
15888
|
-
bundle: string(),
|
|
15889
|
-
/**
|
|
15890
|
-
* Sidebar section this page docks into. Well-known ids: `'detection'`,
|
|
15891
|
-
* `'cluster'`, `'administration'` — the page renders inside that group.
|
|
15892
|
-
* Any OTHER string creates (or joins) a custom section rendered after
|
|
15893
|
-
* the built-in groups; its label comes from `sectionLabel` (first
|
|
15894
|
-
* declaration wins), falling back to the id. Absent → the legacy
|
|
15895
|
-
* "Addon Pages" group.
|
|
15896
|
-
*/
|
|
15897
|
-
section: string().optional(),
|
|
15898
|
-
/** Display label for a CUSTOM `section` id (ignored for well-known ids). */
|
|
15899
|
-
sectionLabel: string().optional()
|
|
15900
|
-
});
|
|
15901
|
-
method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
|
|
15902
16875
|
var AddonHttpRouteSchema = object({
|
|
15903
16876
|
method: _enum([
|
|
15904
16877
|
"GET",
|
|
@@ -16180,9 +17153,21 @@ var AlertSeveritySchema = _enum([
|
|
|
16180
17153
|
"error",
|
|
16181
17154
|
"critical"
|
|
16182
17155
|
]);
|
|
17156
|
+
/**
|
|
17157
|
+
* An action that RUNS something instead of going somewhere: the admin UI calls
|
|
17158
|
+
* the addon's custom action (`addons.custom`) with exactly these fields. The
|
|
17159
|
+
* producer owns the meaning; the UI knows nothing about the addon or the kind.
|
|
17160
|
+
*/
|
|
17161
|
+
var AlertActionInvokeSchema = object({
|
|
17162
|
+
addonId: string().min(1),
|
|
17163
|
+
action: string().min(1),
|
|
17164
|
+
input: record(string(), unknown()).optional()
|
|
17165
|
+
});
|
|
17166
|
+
/** An action has `href` (a link) OR `invoke` (a button that runs a custom action). */
|
|
16183
17167
|
var AlertActionSchema = object({
|
|
16184
17168
|
label: string(),
|
|
16185
17169
|
href: string().optional(),
|
|
17170
|
+
invoke: AlertActionInvokeSchema.optional(),
|
|
16186
17171
|
/**
|
|
16187
17172
|
* How `href` is followed. Absent / `app`: an admin-ui route (client-side).
|
|
16188
17173
|
* `server`: a route the HUB serves (an addon HTTP route such as an OAuth
|
|
@@ -18400,7 +19385,7 @@ var CompositionEventPlanSchema = object({
|
|
|
18400
19385
|
stateField: string(),
|
|
18401
19386
|
fieldKey: string()
|
|
18402
19387
|
});
|
|
18403
|
-
/** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.
|
|
19388
|
+
/** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.temperature`. */
|
|
18404
19389
|
var CompositionProblemSchema = object({
|
|
18405
19390
|
code: _enum([
|
|
18406
19391
|
"reserved-variant",
|
|
@@ -18429,7 +19414,11 @@ var CompositionProblemSchema = object({
|
|
|
18429
19414
|
"mixed-quantity",
|
|
18430
19415
|
"helper-mismatch",
|
|
18431
19416
|
"member-constraint",
|
|
18432
|
-
"retention"
|
|
19417
|
+
"retention",
|
|
19418
|
+
"command-method-unknown",
|
|
19419
|
+
"command-source-unknown",
|
|
19420
|
+
"command-input-unknown",
|
|
19421
|
+
"command-input-missing"
|
|
18433
19422
|
]),
|
|
18434
19423
|
path: string(),
|
|
18435
19424
|
message: string()
|
|
@@ -18468,7 +19457,9 @@ var CompositionFieldRoleSchema = _enum([
|
|
|
18468
19457
|
var CompositionFieldItemSchema = object({
|
|
18469
19458
|
arrayPath: string(),
|
|
18470
19459
|
key: string(),
|
|
18471
|
-
label: string()
|
|
19460
|
+
label: string(),
|
|
19461
|
+
/** True when the item carries a `reset` forward: the composer writes `resettable` from this (D967). */
|
|
19462
|
+
resettable: boolean().optional()
|
|
18472
19463
|
});
|
|
18473
19464
|
var CompositionFieldPlanSchema = object({
|
|
18474
19465
|
cap: string(),
|
|
@@ -18673,7 +19664,7 @@ Object.freeze({
|
|
|
18673
19664
|
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18674
19665
|
* Data, not a form default written into the block.
|
|
18675
19666
|
*/
|
|
18676
|
-
var NOW$
|
|
19667
|
+
var NOW$3 = {
|
|
18677
19668
|
fieldPath: "lastFetchedAt",
|
|
18678
19669
|
expr: "now"
|
|
18679
19670
|
};
|
|
@@ -18682,12 +19673,13 @@ var CHANGED = {
|
|
|
18682
19673
|
expr: "now"
|
|
18683
19674
|
};
|
|
18684
19675
|
function numeric(input) {
|
|
19676
|
+
const { alsoFrom, ...base } = input;
|
|
18685
19677
|
return {
|
|
18686
|
-
...
|
|
19678
|
+
...base,
|
|
18687
19679
|
family: "numeric",
|
|
18688
19680
|
deviceType: DeviceType.Sensor,
|
|
18689
19681
|
memberDeviceType: DeviceType.Sensor,
|
|
18690
|
-
memberDeviceTypes: [DeviceType.Sensor],
|
|
19682
|
+
memberDeviceTypes: [DeviceType.Sensor, ...alsoFrom?.deviceTypes ?? []],
|
|
18691
19683
|
activeWhen: void 0,
|
|
18692
19684
|
commandCaps: [],
|
|
18693
19685
|
baseUnit: baseUnitOf(input.quantity),
|
|
@@ -18695,9 +19687,10 @@ function numeric(input) {
|
|
|
18695
19687
|
accept: [{
|
|
18696
19688
|
cap: input.outputCap,
|
|
18697
19689
|
fieldPath: input.outputField
|
|
18698
|
-
}]
|
|
19690
|
+
}, ...alsoFrom === void 0 ? [] : [alsoFrom.accept]]
|
|
18699
19691
|
};
|
|
18700
19692
|
}
|
|
19693
|
+
var CLIMATE_DEVICES = [DeviceType.Thermostat, DeviceType.Climate];
|
|
18701
19694
|
function binary(input) {
|
|
18702
19695
|
return {
|
|
18703
19696
|
...input,
|
|
@@ -18719,73 +19712,87 @@ var GROUP_TEMPLATES = [
|
|
|
18719
19712
|
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18720
19713
|
role: DeviceRole.TemperatureSensor,
|
|
18721
19714
|
outputCap: "temperature-sensor",
|
|
18722
|
-
outputField: "
|
|
19715
|
+
outputField: "temperature",
|
|
18723
19716
|
quantity: "temperature",
|
|
18724
19717
|
defaultAggregate: "mean",
|
|
18725
19718
|
empty: "null",
|
|
18726
|
-
companions: [NOW$
|
|
19719
|
+
companions: [NOW$3],
|
|
19720
|
+
alsoFrom: {
|
|
19721
|
+
deviceTypes: CLIMATE_DEVICES,
|
|
19722
|
+
accept: {
|
|
19723
|
+
cap: "climate-control",
|
|
19724
|
+
fieldPath: "currentTemp"
|
|
19725
|
+
}
|
|
19726
|
+
}
|
|
18727
19727
|
}),
|
|
18728
19728
|
numeric({
|
|
18729
19729
|
id: "humidity",
|
|
18730
19730
|
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18731
19731
|
role: DeviceRole.HumiditySensor,
|
|
18732
19732
|
outputCap: "humidity-sensor",
|
|
18733
|
-
outputField: "
|
|
19733
|
+
outputField: "humidity",
|
|
18734
19734
|
quantity: "humidity",
|
|
18735
19735
|
defaultAggregate: "mean",
|
|
18736
19736
|
empty: "null",
|
|
18737
|
-
companions: [NOW$
|
|
19737
|
+
companions: [NOW$3],
|
|
19738
|
+
alsoFrom: {
|
|
19739
|
+
deviceTypes: CLIMATE_DEVICES,
|
|
19740
|
+
accept: {
|
|
19741
|
+
cap: "climate-control",
|
|
19742
|
+
fieldPath: "currentHumidity"
|
|
19743
|
+
}
|
|
19744
|
+
}
|
|
18738
19745
|
}),
|
|
18739
19746
|
numeric({
|
|
18740
19747
|
id: "pressure",
|
|
18741
19748
|
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18742
19749
|
role: DeviceRole.PressureSensor,
|
|
18743
19750
|
outputCap: "pressure-sensor",
|
|
18744
|
-
outputField: "
|
|
19751
|
+
outputField: "pressure",
|
|
18745
19752
|
quantity: "pressure",
|
|
18746
19753
|
defaultAggregate: "mean",
|
|
18747
19754
|
empty: "null",
|
|
18748
|
-
companions: [NOW$
|
|
19755
|
+
companions: [NOW$3]
|
|
18749
19756
|
}),
|
|
18750
19757
|
numeric({
|
|
18751
19758
|
id: "illuminance",
|
|
18752
19759
|
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18753
19760
|
role: DeviceRole.AmbientLightSensor,
|
|
18754
19761
|
outputCap: "ambient-light-sensor",
|
|
18755
|
-
outputField: "
|
|
19762
|
+
outputField: "illuminance",
|
|
18756
19763
|
quantity: "illuminance",
|
|
18757
19764
|
defaultAggregate: "mean",
|
|
18758
19765
|
empty: "null",
|
|
18759
|
-
companions: [NOW$
|
|
19766
|
+
companions: [NOW$3]
|
|
18760
19767
|
}),
|
|
18761
19768
|
numeric({
|
|
18762
19769
|
id: "power",
|
|
18763
19770
|
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18764
19771
|
role: DeviceRole.PowerSensor,
|
|
18765
19772
|
outputCap: "power-meter",
|
|
18766
|
-
outputField: "
|
|
19773
|
+
outputField: "power",
|
|
18767
19774
|
quantity: "power",
|
|
18768
19775
|
defaultAggregate: "sum",
|
|
18769
19776
|
empty: "omit",
|
|
18770
|
-
companions: [NOW$
|
|
19777
|
+
companions: [NOW$3]
|
|
18771
19778
|
}),
|
|
18772
19779
|
numeric({
|
|
18773
19780
|
id: "energy",
|
|
18774
19781
|
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18775
19782
|
role: DeviceRole.EnergySensor,
|
|
18776
19783
|
outputCap: "power-meter",
|
|
18777
|
-
outputField: "
|
|
19784
|
+
outputField: "energy",
|
|
18778
19785
|
quantity: "energy",
|
|
18779
19786
|
defaultAggregate: "sum",
|
|
18780
19787
|
empty: "omit",
|
|
18781
|
-
companions: [NOW$
|
|
19788
|
+
companions: [NOW$3]
|
|
18782
19789
|
}),
|
|
18783
19790
|
numeric({
|
|
18784
19791
|
id: "battery",
|
|
18785
19792
|
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18786
19793
|
role: DeviceRole.BatterySensor,
|
|
18787
19794
|
outputCap: "battery",
|
|
18788
|
-
outputField: "
|
|
19795
|
+
outputField: "level",
|
|
18789
19796
|
quantity: "percentage",
|
|
18790
19797
|
defaultAggregate: "mean",
|
|
18791
19798
|
empty: "null",
|
|
@@ -18813,7 +19820,7 @@ var GROUP_TEMPLATES = [
|
|
|
18813
19820
|
quantity: "device",
|
|
18814
19821
|
defaultAggregate: "mean",
|
|
18815
19822
|
empty: "null",
|
|
18816
|
-
companions: [NOW$
|
|
19823
|
+
companions: [NOW$3]
|
|
18817
19824
|
}),
|
|
18818
19825
|
binary({
|
|
18819
19826
|
id: "motion",
|
|
@@ -19363,7 +20370,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
|
|
|
19363
20370
|
kind: "mutation",
|
|
19364
20371
|
auth: "admin",
|
|
19365
20372
|
access: "view"
|
|
19366
|
-
})
|
|
20373
|
+
}), method(object({
|
|
20374
|
+
blockId: string().min(1),
|
|
20375
|
+
trace: AutomationRunTraceSchema.optional(),
|
|
20376
|
+
runStartedAt: number().optional(),
|
|
20377
|
+
keepTraces: number().int().min(1).max(100).optional()
|
|
20378
|
+
}), _void(), {
|
|
20379
|
+
kind: "mutation",
|
|
20380
|
+
auth: "admin"
|
|
20381
|
+
}), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
|
|
20382
|
+
traces: array(AutomationRunTraceSchema),
|
|
20383
|
+
lastError: string().nullable()
|
|
20384
|
+
}), { auth: "admin" });
|
|
19367
20385
|
/**
|
|
19368
20386
|
* `custom-model-registry` — collection cap exposing operator-registered
|
|
19369
20387
|
* custom detection models. Each provider (today: `addon-model-studio`)
|
|
@@ -21148,12 +22166,48 @@ var ExposeInputSchema = object({
|
|
|
21148
22166
|
capabilities: array(string()).optional()
|
|
21149
22167
|
});
|
|
21150
22168
|
var UnexposeInputSchema = object({ deviceId: string() });
|
|
22169
|
+
/**
|
|
22170
|
+
* What an exporter may expose besides devices (D968). An action and a
|
|
22171
|
+
* notification target are LIST ENTRIES, never devices (D954): they enter an
|
|
22172
|
+
* exporter's own selection, not the device registry.
|
|
22173
|
+
*/
|
|
22174
|
+
var ExportEntityKindSchema = _enum([
|
|
22175
|
+
"device",
|
|
22176
|
+
"action",
|
|
22177
|
+
"notifier"
|
|
22178
|
+
]);
|
|
22179
|
+
var ExportEntityRefSchema = discriminatedUnion("kind", [
|
|
22180
|
+
object({
|
|
22181
|
+
kind: literal("device"),
|
|
22182
|
+
deviceId: string()
|
|
22183
|
+
}),
|
|
22184
|
+
object({
|
|
22185
|
+
kind: literal("action"),
|
|
22186
|
+
actionId: string().min(1)
|
|
22187
|
+
}),
|
|
22188
|
+
object({
|
|
22189
|
+
kind: literal("notifier"),
|
|
22190
|
+
targetId: string().min(1)
|
|
22191
|
+
})
|
|
22192
|
+
]);
|
|
22193
|
+
var ExposedEntitySchema = object({
|
|
22194
|
+
entity: ExportEntityRefSchema,
|
|
22195
|
+
exposedAs: string().optional()
|
|
22196
|
+
});
|
|
22197
|
+
var ExposeEntityInputSchema = object({ entity: ExportEntityRefSchema });
|
|
22198
|
+
var UnexposeEntityInputSchema = object({ entity: ExportEntityRefSchema });
|
|
21151
22199
|
method(_void(), DeviceExportStatusSchema), method(_void(), array(DeviceKindSchema)), method(_void(), array(ExposedDeviceSchema)), method(ExposeInputSchema, _void(), {
|
|
21152
22200
|
kind: "mutation",
|
|
21153
22201
|
auth: "admin"
|
|
21154
22202
|
}), method(UnexposeInputSchema, _void(), {
|
|
21155
22203
|
kind: "mutation",
|
|
21156
22204
|
auth: "admin"
|
|
22205
|
+
}), optionalMethod(_void(), array(ExportEntityKindSchema)), optionalMethod(_void(), array(ExposedEntitySchema)), optionalMethod(ExposeEntityInputSchema, _void(), {
|
|
22206
|
+
kind: "mutation",
|
|
22207
|
+
auth: "admin"
|
|
22208
|
+
}), optionalMethod(UnexposeEntityInputSchema, _void(), {
|
|
22209
|
+
kind: "mutation",
|
|
22210
|
+
auth: "admin"
|
|
21157
22211
|
});
|
|
21158
22212
|
/** Lucide category ids, alphabetical. `ICON_META` indexes into this. */
|
|
21159
22213
|
var ICON_CATEGORY_IDS = [
|
|
@@ -42294,6 +43348,14 @@ method(object({
|
|
|
42294
43348
|
kind: "mutation",
|
|
42295
43349
|
auth: "admin"
|
|
42296
43350
|
});
|
|
43351
|
+
method(object({
|
|
43352
|
+
nodeId: string().min(1),
|
|
43353
|
+
/** Epoch ms the node was forgotten (the tombstone's `removedAt`). */
|
|
43354
|
+
removedAt: number()
|
|
43355
|
+
}), object({ counts: record(string(), number().int().nonnegative()) }), {
|
|
43356
|
+
kind: "mutation",
|
|
43357
|
+
auth: "admin"
|
|
43358
|
+
});
|
|
42297
43359
|
/**
|
|
42298
43360
|
* `device-removal-hook` — the reliable way an addon learns a device was DELETED,
|
|
42299
43361
|
* so it can delete what it keeps for that device (D865).
|
|
@@ -42941,6 +44003,17 @@ var LlmProfileSchema = object({
|
|
|
42941
44003
|
* field in its editor only when its descriptor lists it in `profileFields`. */
|
|
42942
44004
|
topK: number().int().positive().optional(),
|
|
42943
44005
|
maxTokens: number().int().positive().optional(),
|
|
44006
|
+
/** How hard the model "thinks" before it answers. Omitted = the model's own
|
|
44007
|
+
* default. `off` matters for structured output: a thinking model can spend
|
|
44008
|
+
* the whole completion on reasoning and return an empty `content`. Carried
|
|
44009
|
+
* only by the wires that have it — a kind offers the field in its editor
|
|
44010
|
+
* only when its descriptor lists it in `profileFields`. */
|
|
44011
|
+
reasoningEffort: _enum([
|
|
44012
|
+
"off",
|
|
44013
|
+
"low",
|
|
44014
|
+
"medium",
|
|
44015
|
+
"high"
|
|
44016
|
+
]).optional(),
|
|
42944
44017
|
/** Prompt context window. Advisory for cloud kinds (they enforce their own). */
|
|
42945
44018
|
contextLength: number().int().positive().optional(),
|
|
42946
44019
|
/** Default system prompt. A caller's `system` REPLACES it (never appends —
|
|
@@ -42979,6 +44052,7 @@ var LlmProfileFieldSchema = _enum([
|
|
|
42979
44052
|
"topP",
|
|
42980
44053
|
"topK",
|
|
42981
44054
|
"maxTokens",
|
|
44055
|
+
"reasoningEffort",
|
|
42982
44056
|
"contextLength",
|
|
42983
44057
|
"systemPrompt",
|
|
42984
44058
|
"timeoutMs",
|
|
@@ -43002,7 +44076,7 @@ var LlmProviderWidgetSchema = object({
|
|
|
43002
44076
|
/** ConfigUISchema tree passed through untyped on the wire (the
|
|
43003
44077
|
* notification-output `ConfigSchemaPassthrough` precedent at
|
|
43004
44078
|
* notification-output.cap.ts:151); the exported TS type re-tightens it. */
|
|
43005
|
-
var ConfigSchemaPassthrough$
|
|
44079
|
+
var ConfigSchemaPassthrough$2 = unknown();
|
|
43006
44080
|
var LlmProfileKindDescriptorSchema = object({
|
|
43007
44081
|
kind: LlmProfileKindSchema,
|
|
43008
44082
|
label: string(),
|
|
@@ -43011,9 +44085,9 @@ var LlmProfileKindDescriptorSchema = object({
|
|
|
43011
44085
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
43012
44086
|
addonId: string(),
|
|
43013
44087
|
/** The provider's own fields (`providerConfig`); `password` fields are keychain-held. */
|
|
43014
|
-
connectionSchema: ConfigSchemaPassthrough$
|
|
44088
|
+
connectionSchema: ConfigSchemaPassthrough$2,
|
|
43015
44089
|
/** Provider fields that belong under "Advanced" (extra headers, runtime tuning). */
|
|
43016
|
-
advancedSchema: ConfigSchemaPassthrough$
|
|
44090
|
+
advancedSchema: ConfigSchemaPassthrough$2.optional(),
|
|
43017
44091
|
/** The kind's defaults; a model from `listModels` may override any of them. */
|
|
43018
44092
|
features: LlmModelFeaturesSchema,
|
|
43019
44093
|
/** `false` = the provider stamps `supportsVision` itself (from what a node reports). */
|
|
@@ -43539,10 +44613,10 @@ var CpuBreakdownSchema = object({
|
|
|
43539
44613
|
cores: number()
|
|
43540
44614
|
});
|
|
43541
44615
|
var MemoryInfoSchema = object({
|
|
43542
|
-
percent: number(),
|
|
44616
|
+
percent: number().nullable(),
|
|
43543
44617
|
totalBytes: number(),
|
|
43544
|
-
usedBytes: number(),
|
|
43545
|
-
availableBytes: number(),
|
|
44618
|
+
usedBytes: number().nullable(),
|
|
44619
|
+
availableBytes: number().nullable(),
|
|
43546
44620
|
swapUsedBytes: number(),
|
|
43547
44621
|
swapTotalBytes: number()
|
|
43548
44622
|
});
|
|
@@ -43846,8 +44920,9 @@ var GetLoadSeriesInputSchema = object({
|
|
|
43846
44920
|
});
|
|
43847
44921
|
var SystemMetricsSchema = object({
|
|
43848
44922
|
cpuPercent: number(),
|
|
43849
|
-
|
|
43850
|
-
|
|
44923
|
+
/** `null` when the memory sample failed or was not taken yet (D393). */
|
|
44924
|
+
memoryPercent: number().nullable(),
|
|
44925
|
+
memoryUsedMB: number().nullable(),
|
|
43851
44926
|
memoryTotalMB: number(),
|
|
43852
44927
|
diskPercent: number().optional(),
|
|
43853
44928
|
temperature: number().optional(),
|
|
@@ -44083,424 +45158,6 @@ var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
|
|
|
44083
45158
|
sourcePort: number().optional()
|
|
44084
45159
|
});
|
|
44085
45160
|
method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
|
|
44086
|
-
/**
|
|
44087
|
-
* notification-output — canonical, capability-gated notification delivery.
|
|
44088
|
-
*
|
|
44089
|
-
* Apprise-derived model (see
|
|
44090
|
-
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
44091
|
-
* callers emit ONE canonical `Notification`; each provider declares a
|
|
44092
|
-
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
44093
|
-
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
44094
|
-
* message to what the kind supports — callers never special-case a service.
|
|
44095
|
-
*
|
|
44096
|
-
* DESIGN DECISIONS (locked):
|
|
44097
|
-
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
44098
|
-
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
44099
|
-
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
44100
|
-
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
44101
|
-
* alternative would fork the UI per addon and cannot host the
|
|
44102
|
-
* discovery→adopt flow.
|
|
44103
|
-
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
44104
|
-
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
44105
|
-
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
44106
|
-
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
44107
|
-
* `addonId` the generated collection router extracts from the call input.
|
|
44108
|
-
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
44109
|
-
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
44110
|
-
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
44111
|
-
* base64 fallback needed.
|
|
44112
|
-
*
|
|
44113
|
-
* TODO (deferred, closed-set change — separate decision): add
|
|
44114
|
-
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
44115
|
-
* admin "Integrations" page.
|
|
44116
|
-
*/
|
|
44117
|
-
/**
|
|
44118
|
-
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
44119
|
-
* adapter picks what it supports and the degrade engine filters the rest.
|
|
44120
|
-
*/
|
|
44121
|
-
var AttachmentMediaTypeSchema = _enum([
|
|
44122
|
-
"image",
|
|
44123
|
-
"video",
|
|
44124
|
-
"gif",
|
|
44125
|
-
"audio",
|
|
44126
|
-
"icon"
|
|
44127
|
-
]);
|
|
44128
|
-
/**
|
|
44129
|
-
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
44130
|
-
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
44131
|
-
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
44132
|
-
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
44133
|
-
*/
|
|
44134
|
-
var AttachmentSchema = object({
|
|
44135
|
-
mediaType: AttachmentMediaTypeSchema,
|
|
44136
|
-
url: string().optional(),
|
|
44137
|
-
bytes: _instanceof(Uint8Array).optional(),
|
|
44138
|
-
mime: string().optional(),
|
|
44139
|
-
name: string().optional()
|
|
44140
|
-
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
44141
|
-
var NotificationFormatSchema = _enum([
|
|
44142
|
-
"text",
|
|
44143
|
-
"markdown",
|
|
44144
|
-
"html"
|
|
44145
|
-
]);
|
|
44146
|
-
/**
|
|
44147
|
-
* The CLOSED icon vocabulary an action button may use.
|
|
44148
|
-
*
|
|
44149
|
-
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
44150
|
-
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
44151
|
-
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
44152
|
-
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
44153
|
-
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
44154
|
-
*
|
|
44155
|
-
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
44156
|
-
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
44157
|
-
* differently.
|
|
44158
|
-
*
|
|
44159
|
-
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
44160
|
-
*
|
|
44161
|
-
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
44162
|
-
* the whole set onto its own renderer's vocabulary through a
|
|
44163
|
-
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
44164
|
-
* fallback, so adding a member here fails every adapter's build until someone
|
|
44165
|
-
* decides its glyph, which is the only place that decision can be made
|
|
44166
|
-
* honestly.
|
|
44167
|
-
*
|
|
44168
|
-
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
44169
|
-
* `disarm` straight through; iOS feeds that string to
|
|
44170
|
-
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
44171
|
-
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
44172
|
-
* mapping, and "the field is documented" is not "the value renders".
|
|
44173
|
-
*
|
|
44174
|
-
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
44175
|
-
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
44176
|
-
* so an addon that emits a token the running hub does not know does not lose an
|
|
44177
|
-
* icon — its whole `send` fails Zod validation and the notification never
|
|
44178
|
-
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
44179
|
-
*/
|
|
44180
|
-
var NotificationActionIconSchema = _enum([
|
|
44181
|
-
"acknowledge",
|
|
44182
|
-
"dismiss",
|
|
44183
|
-
"silence",
|
|
44184
|
-
"snooze",
|
|
44185
|
-
"view",
|
|
44186
|
-
"play",
|
|
44187
|
-
"open",
|
|
44188
|
-
"close",
|
|
44189
|
-
"lock",
|
|
44190
|
-
"unlock",
|
|
44191
|
-
"arm",
|
|
44192
|
-
"arm-home",
|
|
44193
|
-
"arm-away",
|
|
44194
|
-
"arm-night",
|
|
44195
|
-
"disarm",
|
|
44196
|
-
"light",
|
|
44197
|
-
"alert",
|
|
44198
|
-
"camera"
|
|
44199
|
-
]);
|
|
44200
|
-
/** A single tap-through action button. */
|
|
44201
|
-
var NotificationActionSchema = object({
|
|
44202
|
-
id: string(),
|
|
44203
|
-
label: string(),
|
|
44204
|
-
url: string().optional(),
|
|
44205
|
-
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
44206
|
-
icon: NotificationActionIconSchema.optional(),
|
|
44207
|
-
/**
|
|
44208
|
-
* Renders in a warning style where the notifier supports it.
|
|
44209
|
-
*
|
|
44210
|
-
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
44211
|
-
* else — see `notification-center/action-token.ts` for what that does and
|
|
44212
|
-
* does not buy.
|
|
44213
|
-
*/
|
|
44214
|
-
destructive: boolean().optional(),
|
|
44215
|
-
/**
|
|
44216
|
-
* How the tap should REACH the url.
|
|
44217
|
-
*
|
|
44218
|
-
* `navigate` (absent, and every button authored before this field) opens it:
|
|
44219
|
-
* the phone leaves the notification and shows whatever the callback returns.
|
|
44220
|
-
* That is right for a button whose answer the operator wants to read.
|
|
44221
|
-
*
|
|
44222
|
-
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
44223
|
-
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
44224
|
-
* an answer to the notification, and being thrown into a browser tab to
|
|
44225
|
-
* confirm it costs more attention than the notification did. A backend that
|
|
44226
|
-
* cannot do a background call renders it as an ordinary link (the adapters
|
|
44227
|
-
* fall back rather than dropping the button), so this is a preference, never
|
|
44228
|
-
* a requirement.
|
|
44229
|
-
*/
|
|
44230
|
-
mode: _enum(["navigate", "background"]).optional()
|
|
44231
|
-
});
|
|
44232
|
-
/**
|
|
44233
|
-
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
44234
|
-
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
44235
|
-
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
44236
|
-
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
44237
|
-
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
44238
|
-
* `priority` for that one target.
|
|
44239
|
-
*/
|
|
44240
|
-
var NotificationSchema = object({
|
|
44241
|
-
body: string(),
|
|
44242
|
-
title: string().optional(),
|
|
44243
|
-
format: NotificationFormatSchema.default("text"),
|
|
44244
|
-
priority: number().int().min(1).max(5).default(3),
|
|
44245
|
-
level: string().optional(),
|
|
44246
|
-
attachments: array(AttachmentSchema).optional(),
|
|
44247
|
-
clickUrl: string().optional(),
|
|
44248
|
-
actions: array(NotificationActionSchema).optional(),
|
|
44249
|
-
sound: string().optional(),
|
|
44250
|
-
ttl: number().optional(),
|
|
44251
|
-
tag: string().optional(),
|
|
44252
|
-
deviceId: number().optional(),
|
|
44253
|
-
eventId: string().optional(),
|
|
44254
|
-
metadata: record(string(), unknown()).optional()
|
|
44255
|
-
});
|
|
44256
|
-
/** One declared native severity/priority level for a kind. */
|
|
44257
|
-
var TargetKindLevelSchema = object({
|
|
44258
|
-
id: string(),
|
|
44259
|
-
label: string(),
|
|
44260
|
-
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
44261
|
-
ordinal: number().int().min(1).max(5).nullable(),
|
|
44262
|
-
flags: object({
|
|
44263
|
-
critical: boolean().optional(),
|
|
44264
|
-
silent: boolean().optional(),
|
|
44265
|
-
noPush: boolean().optional()
|
|
44266
|
-
}).optional(),
|
|
44267
|
-
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
44268
|
-
requires: array(string()).optional(),
|
|
44269
|
-
description: string().optional()
|
|
44270
|
-
});
|
|
44271
|
-
/** The full capability block consulted before dispatch. */
|
|
44272
|
-
var TargetKindCapsSchema = object({
|
|
44273
|
-
attachments: object({
|
|
44274
|
-
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
44275
|
-
mode: _enum([
|
|
44276
|
-
"url",
|
|
44277
|
-
"bytes",
|
|
44278
|
-
"both"
|
|
44279
|
-
]),
|
|
44280
|
-
max: number().int().nonnegative(),
|
|
44281
|
-
maxBytes: number().int().positive().optional()
|
|
44282
|
-
}),
|
|
44283
|
-
/** Max action buttons (0 = none). */
|
|
44284
|
-
actions: number().int().nonnegative(),
|
|
44285
|
-
/**
|
|
44286
|
-
* Whether this kind renders a per-action ICON.
|
|
44287
|
-
*
|
|
44288
|
-
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
44289
|
-
* run on the addon cap path — three production failures in one day taught
|
|
44290
|
-
* this repo that once. Absent is read as false by the degrade engine, which
|
|
44291
|
-
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
44292
|
-
* assumed and dropped costs the operator's trust in the field.
|
|
44293
|
-
*/
|
|
44294
|
-
actionIcons: boolean().optional(),
|
|
44295
|
-
levels: array(TargetKindLevelSchema),
|
|
44296
|
-
format: array(NotificationFormatSchema),
|
|
44297
|
-
clickUrl: boolean(),
|
|
44298
|
-
sound: boolean(),
|
|
44299
|
-
ttl: boolean(),
|
|
44300
|
-
bodyMaxLen: number().int().positive()
|
|
44301
|
-
});
|
|
44302
|
-
/**
|
|
44303
|
-
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
44304
|
-
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
44305
|
-
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
44306
|
-
* the union is large and not meant for runtime validation here; the exported
|
|
44307
|
-
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
44308
|
-
*/
|
|
44309
|
-
var ConfigSchemaPassthrough$2 = unknown();
|
|
44310
|
-
var TargetKindSchema = object({
|
|
44311
|
-
kind: string(),
|
|
44312
|
-
label: string(),
|
|
44313
|
-
icon: string(),
|
|
44314
|
-
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
44315
|
-
addonId: string(),
|
|
44316
|
-
/**
|
|
44317
|
-
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
44318
|
-
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
44319
|
-
* when the addon bundles no icon for that kind — the client then falls back
|
|
44320
|
-
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
44321
|
-
*
|
|
44322
|
-
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
44323
|
-
* client, and a native client joins it onto its own hub base.
|
|
44324
|
-
*
|
|
44325
|
-
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
44326
|
-
* field that survived only because the runtime cap-router forwards provider
|
|
44327
|
-
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
44328
|
-
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
44329
|
-
* broken silently the moment output validation was tightened anywhere.
|
|
44330
|
-
*/
|
|
44331
|
-
iconUrl: string().optional(),
|
|
44332
|
-
/**
|
|
44333
|
-
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
44334
|
-
*
|
|
44335
|
-
* The server knows this and therefore says it, because the client cannot
|
|
44336
|
-
* safely guess: a React-Native client renders SVG and raster through two
|
|
44337
|
-
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
44338
|
-
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
44339
|
-
* placeholder glyph for every vector icon while the web build looked fine.
|
|
44340
|
-
*
|
|
44341
|
-
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
44342
|
-
* not been updated — a client that cannot determine the type should prefer
|
|
44343
|
-
* its raster path, which is the safe default for an unknown image.
|
|
44344
|
-
*/
|
|
44345
|
-
iconMediaType: string().optional(),
|
|
44346
|
-
configSchema: ConfigSchemaPassthrough$2,
|
|
44347
|
-
/**
|
|
44348
|
-
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
44349
|
-
* base URL, instance, chat, recipient). A save that changes any of them
|
|
44350
|
-
* while leaving a secret redacted is refused by the provider (D634), so an
|
|
44351
|
-
* editor uses this to ask for the secret on exactly those edits instead of
|
|
44352
|
-
* on every edit.
|
|
44353
|
-
*
|
|
44354
|
-
* Optional: absent from a provider that holds no secret (the Home Assistant
|
|
44355
|
-
* kinds) and from a provider older than this field — an editor that finds
|
|
44356
|
-
* it absent must assume ANY edit may need the secret.
|
|
44357
|
-
*/
|
|
44358
|
-
destinationKeys: array(string()).optional(),
|
|
44359
|
-
supportsDiscovery: boolean(),
|
|
44360
|
-
caps: TargetKindCapsSchema
|
|
44361
|
-
});
|
|
44362
|
-
/**
|
|
44363
|
-
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
44364
|
-
* (return a presence marker only) when serving `listTargets` — never
|
|
44365
|
-
* round-trip a stored secret to the UI.
|
|
44366
|
-
*/
|
|
44367
|
-
var TargetSchema = object({
|
|
44368
|
-
id: string(),
|
|
44369
|
-
name: string(),
|
|
44370
|
-
kind: string(),
|
|
44371
|
-
addonId: string(),
|
|
44372
|
-
enabled: boolean(),
|
|
44373
|
-
config: record(string(), unknown())
|
|
44374
|
-
});
|
|
44375
|
-
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
44376
|
-
var DiscoveredTargetSchema = object({
|
|
44377
|
-
kind: string(),
|
|
44378
|
-
suggestedName: string(),
|
|
44379
|
-
config: record(string(), unknown())
|
|
44380
|
-
});
|
|
44381
|
-
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
44382
|
-
var RenderedAsSchema = object({
|
|
44383
|
-
level: string(),
|
|
44384
|
-
format: NotificationFormatSchema,
|
|
44385
|
-
attachmentsSent: number().int().nonnegative(),
|
|
44386
|
-
actionsSent: number().int().nonnegative(),
|
|
44387
|
-
truncated: boolean(),
|
|
44388
|
-
dropped: array(string())
|
|
44389
|
-
});
|
|
44390
|
-
var SendResultSchema = object({
|
|
44391
|
-
success: boolean(),
|
|
44392
|
-
error: string().optional(),
|
|
44393
|
-
renderedAs: RenderedAsSchema.optional()
|
|
44394
|
-
});
|
|
44395
|
-
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
44396
|
-
var TestResultSchema = SendResultSchema;
|
|
44397
|
-
/**
|
|
44398
|
-
* Pre-save credential probe against a partial (unsaved) target config.
|
|
44399
|
-
* `resolvedUrl` never includes secrets (token stripped from path).
|
|
44400
|
-
*/
|
|
44401
|
-
var ProbeTargetConfigResultSchema = object({
|
|
44402
|
-
ok: boolean(),
|
|
44403
|
-
resolvedUrl: string(),
|
|
44404
|
-
httpStatus: number().int().optional(),
|
|
44405
|
-
stateInstance: string().optional(),
|
|
44406
|
-
error: string().optional()
|
|
44407
|
-
});
|
|
44408
|
-
method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema), { auth: "admin" }), method(object({ targetId: string() }), TargetSchema, { auth: "admin" }), method(object({
|
|
44409
|
-
kind: string(),
|
|
44410
|
-
config: record(string(), unknown()).optional(),
|
|
44411
|
-
/**
|
|
44412
|
-
* When editing / duplicating, the blank password field never round-trips
|
|
44413
|
-
* the stored token. Pass the source target id so the provider can restore
|
|
44414
|
-
* secrets server-side before dialling (same merge as upsert).
|
|
44415
|
-
*/
|
|
44416
|
-
targetId: string().optional()
|
|
44417
|
-
}), array(DiscoveredTargetSchema), { auth: "admin" }), method(object({
|
|
44418
|
-
kind: string(),
|
|
44419
|
-
config: record(string(), unknown()),
|
|
44420
|
-
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
44421
|
-
targetId: string().optional()
|
|
44422
|
-
}), ProbeTargetConfigResultSchema, {
|
|
44423
|
-
kind: "mutation",
|
|
44424
|
-
auth: "admin"
|
|
44425
|
-
}), method(object({
|
|
44426
|
-
targetId: string(),
|
|
44427
|
-
notification: NotificationSchema
|
|
44428
|
-
}), SendResultSchema, {
|
|
44429
|
-
kind: "mutation",
|
|
44430
|
-
auth: "admin"
|
|
44431
|
-
}), method(object({
|
|
44432
|
-
targetId: string(),
|
|
44433
|
-
sample: NotificationSchema.optional()
|
|
44434
|
-
}), TestResultSchema, {
|
|
44435
|
-
kind: "mutation",
|
|
44436
|
-
auth: "admin"
|
|
44437
|
-
}), method(object({
|
|
44438
|
-
target: TargetSchema,
|
|
44439
|
-
/**
|
|
44440
|
-
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
44441
|
-
* existing row. The UI never holds the stored token; blank / redacted
|
|
44442
|
-
* password fields are restored from this source (D634 still applies if
|
|
44443
|
-
* destinations diverge without a re-typed secret).
|
|
44444
|
-
*/
|
|
44445
|
-
cloneSecretsFrom: string().optional()
|
|
44446
|
-
}), TargetSchema, {
|
|
44447
|
-
kind: "mutation",
|
|
44448
|
-
auth: "admin"
|
|
44449
|
-
}), method(object({ targetId: string() }), _void(), {
|
|
44450
|
-
kind: "mutation",
|
|
44451
|
-
auth: "admin"
|
|
44452
|
-
}), method(object({
|
|
44453
|
-
targetId: string(),
|
|
44454
|
-
enabled: boolean()
|
|
44455
|
-
}), _void(), {
|
|
44456
|
-
kind: "mutation",
|
|
44457
|
-
auth: "admin"
|
|
44458
|
-
});
|
|
44459
|
-
new Set([
|
|
44460
|
-
{
|
|
44461
|
-
id: "person",
|
|
44462
|
-
name: "Person"
|
|
44463
|
-
},
|
|
44464
|
-
{
|
|
44465
|
-
id: "vehicle",
|
|
44466
|
-
name: "Vehicle"
|
|
44467
|
-
},
|
|
44468
|
-
{
|
|
44469
|
-
id: "animal",
|
|
44470
|
-
name: "Animal"
|
|
44471
|
-
},
|
|
44472
|
-
{
|
|
44473
|
-
id: "package",
|
|
44474
|
-
name: "Package"
|
|
44475
|
-
}
|
|
44476
|
-
].map((l) => l.id));
|
|
44477
|
-
var COCO_TO_MACRO = {
|
|
44478
|
-
mapping: {
|
|
44479
|
-
person: "person",
|
|
44480
|
-
bicycle: "vehicle",
|
|
44481
|
-
car: "vehicle",
|
|
44482
|
-
motorcycle: "vehicle",
|
|
44483
|
-
airplane: "vehicle",
|
|
44484
|
-
bus: "vehicle",
|
|
44485
|
-
train: "vehicle",
|
|
44486
|
-
truck: "vehicle",
|
|
44487
|
-
boat: "vehicle",
|
|
44488
|
-
bird: "animal",
|
|
44489
|
-
cat: "animal",
|
|
44490
|
-
dog: "animal",
|
|
44491
|
-
horse: "animal",
|
|
44492
|
-
sheep: "animal",
|
|
44493
|
-
cow: "animal",
|
|
44494
|
-
elephant: "animal",
|
|
44495
|
-
bear: "animal",
|
|
44496
|
-
zebra: "animal",
|
|
44497
|
-
giraffe: "animal",
|
|
44498
|
-
suitcase: "package",
|
|
44499
|
-
backpack: "package",
|
|
44500
|
-
handbag: "package"
|
|
44501
|
-
},
|
|
44502
|
-
preserveOriginal: false
|
|
44503
|
-
};
|
|
44504
45161
|
var AUDIO_MACRO_LABELS = [
|
|
44505
45162
|
{
|
|
44506
45163
|
id: "speech",
|
|
@@ -50901,14 +51558,6 @@ var EngineProvisioningSchema = object({
|
|
|
50901
51558
|
*/
|
|
50902
51559
|
configIssues: array(string()).optional()
|
|
50903
51560
|
});
|
|
50904
|
-
var PipelineStepInputSchema = lazy(() => object({
|
|
50905
|
-
addonId: string(),
|
|
50906
|
-
modelId: string().optional(),
|
|
50907
|
-
enabled: boolean().default(true),
|
|
50908
|
-
children: array(PipelineStepInputSchema).optional(),
|
|
50909
|
-
settings: record(string(), unknown()).optional(),
|
|
50910
|
-
jumpDeviceKey: string().optional()
|
|
50911
|
-
}));
|
|
50912
51561
|
var ModelSubstitutionSchema = object({
|
|
50913
51562
|
addonId: string(),
|
|
50914
51563
|
chosen: string(),
|
|
@@ -50987,7 +51636,6 @@ var ConfigUISchemaBridge = custom();
|
|
|
50987
51636
|
var ConfigUISchemaNullableBridge = custom();
|
|
50988
51637
|
var InferenceCapabilitiesBridge = custom();
|
|
50989
51638
|
var ModelAvailabilityListBridge = custom();
|
|
50990
|
-
var PipelineRunResultBridge = custom();
|
|
50991
51639
|
method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
|
|
50992
51640
|
modelId: string(),
|
|
50993
51641
|
settings: record(string(), unknown()).readonly()
|
|
@@ -54149,6 +54797,12 @@ var ServerUpdateActionResultSchema = object({
|
|
|
54149
54797
|
*/
|
|
54150
54798
|
blockers: array(UpdateBlockerSchema).optional()
|
|
54151
54799
|
});
|
|
54800
|
+
var LaunchOverridesSchema = object({
|
|
54801
|
+
/** The persisted heap ceiling in MB, or `null` when none is set. */
|
|
54802
|
+
heapMb: number().int().nullable() });
|
|
54803
|
+
var SetLaunchOverridesResultSchema = LaunchOverridesSchema.extend({
|
|
54804
|
+
/** Always true: the override is read at launch, not by the running process. */
|
|
54805
|
+
restartRequired: boolean() });
|
|
54152
54806
|
method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), ServerUpdateCheckResultSchema, {
|
|
54153
54807
|
kind: "mutation",
|
|
54154
54808
|
auth: "admin"
|
|
@@ -54171,6 +54825,9 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
|
|
|
54171
54825
|
}), method(_void(), ServerUpdateActionResultSchema, {
|
|
54172
54826
|
kind: "mutation",
|
|
54173
54827
|
auth: "admin"
|
|
54828
|
+
}), method(_void(), LaunchOverridesSchema, { auth: "admin" }), method(object({ heapMb: number().int().min(512).max(65536).nullable() }), SetLaunchOverridesResultSchema, {
|
|
54829
|
+
kind: "mutation",
|
|
54830
|
+
auth: "admin"
|
|
54174
54831
|
});
|
|
54175
54832
|
/**
|
|
54176
54833
|
* `smtp-provider` — pluggable email delivery surface.
|
|
@@ -56572,7 +57229,9 @@ var ManifestShapeSchema = object({
|
|
|
56572
57229
|
icon: string().optional()
|
|
56573
57230
|
}).optional(),
|
|
56574
57231
|
protected: boolean().optional(),
|
|
56575
|
-
removable: boolean().optional()
|
|
57232
|
+
removable: boolean().optional(),
|
|
57233
|
+
/** Declared Integrations-page block (mirror of `AddonDeclaration.integrationSection`). */
|
|
57234
|
+
integrationSection: _enum(["system", "providers"]).optional()
|
|
56576
57235
|
});
|
|
56577
57236
|
var AddonProcessSchema = object({
|
|
56578
57237
|
pid: number().optional(),
|
|
@@ -56937,9 +57596,9 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56937
57596
|
}), LogStreamEntrySchema, { kind: "subscription" });
|
|
56938
57597
|
object({
|
|
56939
57598
|
/** Carbon dioxide concentration in ppm. */
|
|
56940
|
-
|
|
57599
|
+
co2: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56941
57600
|
/** Total volatile organic compounds in ppb. */
|
|
56942
|
-
|
|
57601
|
+
voc: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56943
57602
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56944
57603
|
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56945
57604
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
@@ -56952,7 +57611,7 @@ object({
|
|
|
56952
57611
|
DeviceType.Sensor;
|
|
56953
57612
|
object({
|
|
56954
57613
|
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
56955
|
-
|
|
57614
|
+
illuminance: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
56956
57615
|
precision: 0,
|
|
56957
57616
|
label: "Illuminance"
|
|
56958
57617
|
})),
|
|
@@ -57049,6 +57708,84 @@ DeviceType.Camera, method(object({ deviceId: number() }), AudioMetricsSnapshotSc
|
|
|
57049
57708
|
* would produce more than `maxPoints` samples. */
|
|
57050
57709
|
sampleEveryMs: number().int().positive().optional()
|
|
57051
57710
|
}), AudioMetricsHistorySchema);
|
|
57711
|
+
method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
|
|
57712
|
+
actionId: string().min(1),
|
|
57713
|
+
variables: record(string(), ActionVariableValueSchema).optional()
|
|
57714
|
+
}), _void(), {
|
|
57715
|
+
kind: "mutation",
|
|
57716
|
+
auth: "admin"
|
|
57717
|
+
}), method(object({ actionId: string().min(1) }), _void(), {
|
|
57718
|
+
kind: "mutation",
|
|
57719
|
+
auth: "admin"
|
|
57720
|
+
});
|
|
57721
|
+
/**
|
|
57722
|
+
* actions — the ONE surface for runnable actions, for the UI and for
|
|
57723
|
+
* automations. Provided by the core-blocks builtin on the hub.
|
|
57724
|
+
*
|
|
57725
|
+
* An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
|
|
57726
|
+
* steps, kept in the hub's `actions` record kind) or declared by an addon over
|
|
57727
|
+
* `action-source`. `list` asks every `action-source` provider LIVE and overlays
|
|
57728
|
+
* the run status from the hub's `runs` ledger; there is no catalog here to
|
|
57729
|
+
* drift (D3).
|
|
57730
|
+
*
|
|
57731
|
+
* **Permissions follow the camera, as linked devices do.** An action is linked
|
|
57732
|
+
* to cameras by the operator (`setLinks`, D356: nothing links itself). A
|
|
57733
|
+
* non-admin may `get` / `run` an action only through a camera they may see that
|
|
57734
|
+
* links it: they name the camera (`deviceId`, a top-level field so the scope
|
|
57735
|
+
* gate sees it) and the provider refuses an action that camera does not link.
|
|
57736
|
+
* An admin, and an in-process caller (an automation block), may run any action.
|
|
57737
|
+
* Every refusal is typed (`[not-linked] …`) and logged.
|
|
57738
|
+
*
|
|
57739
|
+
* A second `run` of an action that is already running is REFUSED — traced and
|
|
57740
|
+
* logged — never queued.
|
|
57741
|
+
*/
|
|
57742
|
+
var ActionIdInput = object({ actionId: string().min(1) });
|
|
57743
|
+
var ActionLinksSchema = object({
|
|
57744
|
+
deviceId: number().int().nonnegative(),
|
|
57745
|
+
actionIds: array(string().min(1)).max(100)
|
|
57746
|
+
});
|
|
57747
|
+
method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
|
|
57748
|
+
actionId: string().min(1),
|
|
57749
|
+
deviceId: number().int().nonnegative().optional()
|
|
57750
|
+
}), object({ action: ActionEntrySchema.nullable() }), {
|
|
57751
|
+
role: "viewer",
|
|
57752
|
+
auth: "protected",
|
|
57753
|
+
kind: "query",
|
|
57754
|
+
caller: "required"
|
|
57755
|
+
}), method(object({
|
|
57756
|
+
actionId: string().min(1),
|
|
57757
|
+
variables: record(string(), ActionVariableValueSchema).optional(),
|
|
57758
|
+
wait: boolean().optional(),
|
|
57759
|
+
origin: ActionRunOriginSchema.optional(),
|
|
57760
|
+
deviceId: number().int().nonnegative().optional()
|
|
57761
|
+
}), ActionRunResultSchema, {
|
|
57762
|
+
role: "viewer",
|
|
57763
|
+
auth: "protected",
|
|
57764
|
+
kind: "mutation",
|
|
57765
|
+
caller: "required"
|
|
57766
|
+
}), method(ActionIdInput, _void(), {
|
|
57767
|
+
kind: "mutation",
|
|
57768
|
+
auth: "admin"
|
|
57769
|
+
}), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
|
|
57770
|
+
kind: "mutation",
|
|
57771
|
+
auth: "admin"
|
|
57772
|
+
}), method(object({
|
|
57773
|
+
actionId: string().min(1),
|
|
57774
|
+
action: ActionInputSchema.partial()
|
|
57775
|
+
}), object({ action: ActionEntrySchema }), {
|
|
57776
|
+
kind: "mutation",
|
|
57777
|
+
auth: "admin"
|
|
57778
|
+
}), method(ActionIdInput, _void(), {
|
|
57779
|
+
kind: "mutation",
|
|
57780
|
+
auth: "admin"
|
|
57781
|
+
}), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
|
|
57782
|
+
role: "viewer",
|
|
57783
|
+
auth: "protected",
|
|
57784
|
+
kind: "query"
|
|
57785
|
+
}), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
|
|
57786
|
+
kind: "mutation",
|
|
57787
|
+
auth: "admin"
|
|
57788
|
+
});
|
|
57052
57789
|
object({
|
|
57053
57790
|
/** Whether the automation is currently enabled. Disabled automations
|
|
57054
57791
|
* ignore their trigger block — manual `trigger` still works. */
|
|
@@ -57102,7 +57839,7 @@ var BatteryStatusSchema = object({
|
|
|
57102
57839
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
57103
57840
|
* declines to band a non-finite reading, which is the correct shape.
|
|
57104
57841
|
*/
|
|
57105
|
-
|
|
57842
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
57106
57843
|
/**
|
|
57107
57844
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
57108
57845
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -57112,7 +57849,7 @@ var BatteryStatusSchema = object({
|
|
|
57112
57849
|
* `'unknown'` is the absence of an answer: the provider has not read the
|
|
57113
57850
|
* power fields yet, or the firmware reported neither. Before it existed,
|
|
57114
57851
|
* two unreadable fields produced `'none'`, and a camera nobody had reached
|
|
57115
|
-
* was drawn "on battery alone" — the same D315 defect `
|
|
57852
|
+
* was drawn "on battery alone" — the same D315 defect `level` closed
|
|
57116
57853
|
* by going nullable. Consumers SKIP it (no charger state published, no
|
|
57117
57854
|
* glyph, no HomeKit ChargingState) rather than coerce it either way.
|
|
57118
57855
|
*/
|
|
@@ -57136,7 +57873,7 @@ var BatteryStatusSchema = object({
|
|
|
57136
57873
|
* that only report charge. A second reading on this cap, not a second
|
|
57137
57874
|
* `numeric-sensor` on the same device.
|
|
57138
57875
|
*/
|
|
57139
|
-
|
|
57876
|
+
voltage: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
57140
57877
|
/**
|
|
57141
57878
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
57142
57879
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -57170,7 +57907,7 @@ var BatteryStatusSchema = object({
|
|
|
57170
57907
|
/**
|
|
57171
57908
|
* True when the source is a BINARY low-battery indicator (HA
|
|
57172
57909
|
* `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
|
|
57173
|
-
* charge level — `
|
|
57910
|
+
* charge level — `level` is then a coarse stand-in (100 = normal,
|
|
57174
57911
|
* sub-threshold = low). UI MUST render "Normal"/"Low" instead of a
|
|
57175
57912
|
* misleading exact percentage. Absent/false → genuine 0–100 % reading.
|
|
57176
57913
|
*/
|
|
@@ -57196,26 +57933,388 @@ object({
|
|
|
57196
57933
|
DeviceType.Sensor;
|
|
57197
57934
|
object({
|
|
57198
57935
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
57199
|
-
|
|
57936
|
+
level: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
57200
57937
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
57201
57938
|
lastChangedAt: number()
|
|
57202
57939
|
});
|
|
57203
57940
|
DeviceType.Light, method(object({
|
|
57204
57941
|
deviceId: number().int().nonnegative(),
|
|
57205
|
-
|
|
57942
|
+
level: number().min(0).max(100)
|
|
57206
57943
|
}), _void(), {
|
|
57207
57944
|
kind: "mutation",
|
|
57208
57945
|
auth: "protected"
|
|
57209
57946
|
}), object({
|
|
57210
57947
|
deviceId: number(),
|
|
57211
|
-
|
|
57948
|
+
level: number().min(0).max(100),
|
|
57212
57949
|
lastChangedAt: number()
|
|
57213
57950
|
});
|
|
57951
|
+
/**
|
|
57952
|
+
* The role vocabulary of a remote (D963): what a button MEANS, independent of
|
|
57953
|
+
* how it is wired. A layout template places buttons by role; a device binds a
|
|
57954
|
+
* role to an action; an exporter asks for a role by name. Roles are shared so
|
|
57955
|
+
* one layout fits every appliance and one voice command fits every binding.
|
|
57956
|
+
*
|
|
57957
|
+
* A role outside this list is `custom:<key>` — the operator's own button (a
|
|
57958
|
+
* SmartIR source, a channel preset). The key is a lowercase slug.
|
|
57959
|
+
*/
|
|
57960
|
+
var REMOTE_KNOWN_ROLES = [
|
|
57961
|
+
"power",
|
|
57962
|
+
"power_on",
|
|
57963
|
+
"power_off",
|
|
57964
|
+
"volume_up",
|
|
57965
|
+
"volume_down",
|
|
57966
|
+
"mute",
|
|
57967
|
+
"channel_up",
|
|
57968
|
+
"channel_down",
|
|
57969
|
+
"up",
|
|
57970
|
+
"down",
|
|
57971
|
+
"left",
|
|
57972
|
+
"right",
|
|
57973
|
+
"ok",
|
|
57974
|
+
"back",
|
|
57975
|
+
"home",
|
|
57976
|
+
"menu",
|
|
57977
|
+
"info",
|
|
57978
|
+
"guide",
|
|
57979
|
+
"exit",
|
|
57980
|
+
"input",
|
|
57981
|
+
"play",
|
|
57982
|
+
"pause",
|
|
57983
|
+
"play_pause",
|
|
57984
|
+
"stop",
|
|
57985
|
+
"next",
|
|
57986
|
+
"previous",
|
|
57987
|
+
"fast_forward",
|
|
57988
|
+
"rewind",
|
|
57989
|
+
"digit_0",
|
|
57990
|
+
"digit_1",
|
|
57991
|
+
"digit_2",
|
|
57992
|
+
"digit_3",
|
|
57993
|
+
"digit_4",
|
|
57994
|
+
"digit_5",
|
|
57995
|
+
"digit_6",
|
|
57996
|
+
"digit_7",
|
|
57997
|
+
"digit_8",
|
|
57998
|
+
"digit_9"
|
|
57999
|
+
];
|
|
58000
|
+
var CUSTOM_KEY_RE = /^[a-z0-9][a-z0-9_]{0,47}$/;
|
|
58001
|
+
var KNOWN_ROLES = new Set(REMOTE_KNOWN_ROLES);
|
|
58002
|
+
function isRemoteKnownRole(value) {
|
|
58003
|
+
return KNOWN_ROLES.has(value);
|
|
58004
|
+
}
|
|
58005
|
+
function isRemoteCustomKey(key) {
|
|
58006
|
+
return CUSTOM_KEY_RE.test(key);
|
|
58007
|
+
}
|
|
58008
|
+
/** The key of a `custom:<key>` role, or null for any other string. */
|
|
58009
|
+
function customKeyOfRole(role) {
|
|
58010
|
+
if (!role.startsWith("custom:")) return null;
|
|
58011
|
+
const key = role.slice(7);
|
|
58012
|
+
return isRemoteCustomKey(key) ? key : null;
|
|
58013
|
+
}
|
|
58014
|
+
function isRemoteRole(value) {
|
|
58015
|
+
return isRemoteKnownRole(value) || customKeyOfRole(value) !== null;
|
|
58016
|
+
}
|
|
58017
|
+
var RemoteRoleSchema = string().refine(isRemoteRole, { message: "a role is one of the known roles or custom:<key> (lowercase letters, digits, _)" });
|
|
58018
|
+
var RemoteBindingSchema = object({ action: AutomationCapStepSchema.extend({ deviceId: number().int().nonnegative() }) });
|
|
58019
|
+
var RemoteCustomButtonSchema = object({
|
|
58020
|
+
/** The slug after `custom:` in the role. */
|
|
58021
|
+
key: string().refine(isRemoteCustomKey, { message: "a lowercase slug" }),
|
|
58022
|
+
/** What the operator calls it, and what a voice command may name. */
|
|
58023
|
+
name: string().min(1).max(60)
|
|
58024
|
+
});
|
|
58025
|
+
var RemotePowerModeSchema = _enum(["toggle", "discrete"]);
|
|
58026
|
+
var RemoteConfigSchema = object({
|
|
58027
|
+
layoutTemplateId: string().min(1).nullable(),
|
|
58028
|
+
/**
|
|
58029
|
+
* The transmitter device new bindings and an import send through. A binding
|
|
58030
|
+
* names its own device, so one command may override it.
|
|
58031
|
+
*/
|
|
58032
|
+
defaultTransmitterId: number().int().nonnegative().nullable().default(null),
|
|
58033
|
+
/** Keyed by role. A role with no entry falls back to the native cap. */
|
|
58034
|
+
bindings: record(string(), RemoteBindingSchema),
|
|
58035
|
+
customButtons: array(RemoteCustomButtonSchema).max(100),
|
|
58036
|
+
power: object({ mode: RemotePowerModeSchema })
|
|
58037
|
+
}).superRefine((config, ctx) => {
|
|
58038
|
+
const roles = Object.keys(config.bindings);
|
|
58039
|
+
if (roles.length > 200) ctx.addIssue({
|
|
58040
|
+
code: "custom",
|
|
58041
|
+
message: "too many bindings",
|
|
58042
|
+
path: ["bindings"]
|
|
58043
|
+
});
|
|
58044
|
+
for (const role of roles) if (!isRemoteRole(role)) ctx.addIssue({
|
|
58045
|
+
code: "custom",
|
|
58046
|
+
message: `"${role}" is not a role`,
|
|
58047
|
+
path: ["bindings", role]
|
|
58048
|
+
});
|
|
58049
|
+
const keys = /* @__PURE__ */ new Set();
|
|
58050
|
+
config.customButtons.forEach((button, index) => {
|
|
58051
|
+
if (keys.has(button.key)) ctx.addIssue({
|
|
58052
|
+
code: "custom",
|
|
58053
|
+
message: `custom button "${button.key}" is listed twice`,
|
|
58054
|
+
path: [
|
|
58055
|
+
"customButtons",
|
|
58056
|
+
index,
|
|
58057
|
+
"key"
|
|
58058
|
+
]
|
|
58059
|
+
});
|
|
58060
|
+
keys.add(button.key);
|
|
58061
|
+
});
|
|
58062
|
+
for (const role of roles) {
|
|
58063
|
+
const key = customKeyOfRole(role);
|
|
58064
|
+
if (key !== null && !keys.has(key)) ctx.addIssue({
|
|
58065
|
+
code: "custom",
|
|
58066
|
+
message: `${role} is bound but has no entry in customButtons`,
|
|
58067
|
+
path: ["bindings", role]
|
|
58068
|
+
});
|
|
58069
|
+
}
|
|
58070
|
+
});
|
|
58071
|
+
object({
|
|
58072
|
+
power: object({
|
|
58073
|
+
state: _enum(["on", "off"]),
|
|
58074
|
+
at: number()
|
|
58075
|
+
}).nullable(),
|
|
58076
|
+
muted: object({
|
|
58077
|
+
value: boolean(),
|
|
58078
|
+
at: number()
|
|
58079
|
+
}).nullable()
|
|
58080
|
+
});
|
|
58081
|
+
var RemoteLayoutButtonSchema = object({
|
|
58082
|
+
id: string().min(1).max(40),
|
|
58083
|
+
/** 0-based grid position. */
|
|
58084
|
+
row: number().int().min(0).max(24),
|
|
58085
|
+
col: number().int().min(0).max(24),
|
|
58086
|
+
rowSpan: number().int().min(1).max(24),
|
|
58087
|
+
colSpan: number().int().min(1).max(24),
|
|
58088
|
+
icon: string().min(1).max(60).optional(),
|
|
58089
|
+
label: string().min(1).max(40).optional(),
|
|
58090
|
+
role: RemoteRoleSchema
|
|
58091
|
+
});
|
|
58092
|
+
object({
|
|
58093
|
+
columns: number().int().min(1).max(24),
|
|
58094
|
+
rows: number().int().min(1).max(24),
|
|
58095
|
+
buttons: array(RemoteLayoutButtonSchema).max(200)
|
|
58096
|
+
}).superRefine((grid, ctx) => {
|
|
58097
|
+
const ids = /* @__PURE__ */ new Set();
|
|
58098
|
+
const taken = /* @__PURE__ */ new Map();
|
|
58099
|
+
grid.buttons.forEach((button, index) => {
|
|
58100
|
+
if (ids.has(button.id)) ctx.addIssue({
|
|
58101
|
+
code: "custom",
|
|
58102
|
+
message: `button id "${button.id}" is used twice`,
|
|
58103
|
+
path: [
|
|
58104
|
+
"buttons",
|
|
58105
|
+
index,
|
|
58106
|
+
"id"
|
|
58107
|
+
]
|
|
58108
|
+
});
|
|
58109
|
+
ids.add(button.id);
|
|
58110
|
+
if (button.row + button.rowSpan > grid.rows || button.col + button.colSpan > grid.columns) {
|
|
58111
|
+
ctx.addIssue({
|
|
58112
|
+
code: "custom",
|
|
58113
|
+
message: `button "${button.id}" leaves the grid`,
|
|
58114
|
+
path: ["buttons", index]
|
|
58115
|
+
});
|
|
58116
|
+
return;
|
|
58117
|
+
}
|
|
58118
|
+
for (let r = button.row; r < button.row + button.rowSpan; r += 1) for (let c = button.col; c < button.col + button.colSpan; c += 1) {
|
|
58119
|
+
const cell = `${r}:${c}`;
|
|
58120
|
+
const other = taken.get(cell);
|
|
58121
|
+
if (other !== void 0) {
|
|
58122
|
+
ctx.addIssue({
|
|
58123
|
+
code: "custom",
|
|
58124
|
+
message: `buttons "${other}" and "${button.id}" overlap`,
|
|
58125
|
+
path: ["buttons", index]
|
|
58126
|
+
});
|
|
58127
|
+
return;
|
|
58128
|
+
}
|
|
58129
|
+
taken.set(cell, button.id);
|
|
58130
|
+
}
|
|
58131
|
+
});
|
|
58132
|
+
});
|
|
58133
|
+
var RemoteBoundCommandSchema = object({
|
|
58134
|
+
role: RemoteRoleSchema,
|
|
58135
|
+
/** The operator's name for a custom button; absent for a known role. */
|
|
58136
|
+
label: string().optional(),
|
|
58137
|
+
custom: boolean()
|
|
58138
|
+
});
|
|
58139
|
+
var RemoteCommandListSchema = object({
|
|
58140
|
+
layoutTemplateId: string().nullable(),
|
|
58141
|
+
power: object({ mode: RemotePowerModeSchema }),
|
|
58142
|
+
/** Only the roles that are BOUND — the ones a press can reach. */
|
|
58143
|
+
commands: array(RemoteBoundCommandSchema)
|
|
58144
|
+
});
|
|
58145
|
+
var RemoteRefusalReasonSchema = _enum([
|
|
58146
|
+
"no-remote",
|
|
58147
|
+
"unbound-role",
|
|
58148
|
+
"action-failed"
|
|
58149
|
+
]);
|
|
58150
|
+
var RemoteSendResultSchema = discriminatedUnion("status", [
|
|
58151
|
+
object({
|
|
58152
|
+
status: literal("sent"),
|
|
58153
|
+
/** How many times the action ran. */
|
|
58154
|
+
sends: number().int().min(1)
|
|
58155
|
+
}),
|
|
58156
|
+
object({
|
|
58157
|
+
status: literal("skipped"),
|
|
58158
|
+
reason: literal("already-in-state")
|
|
58159
|
+
}),
|
|
58160
|
+
object({
|
|
58161
|
+
status: literal("refused"),
|
|
58162
|
+
reason: RemoteRefusalReasonSchema,
|
|
58163
|
+
detail: string().optional()
|
|
58164
|
+
})
|
|
58165
|
+
]);
|
|
58166
|
+
var RemoteMediaCommandSchema = _enum([
|
|
58167
|
+
"play",
|
|
58168
|
+
"pause",
|
|
58169
|
+
"stop",
|
|
58170
|
+
"next",
|
|
58171
|
+
"previous",
|
|
58172
|
+
"setMute",
|
|
58173
|
+
"selectSource"
|
|
58174
|
+
]);
|
|
58175
|
+
/** A send result, or `not-routed`: the role is not bound, so the native cap answers. */
|
|
58176
|
+
var RemoteMediaCommandResultSchema = discriminatedUnion("status", [...RemoteSendResultSchema.options, object({ status: literal("not-routed") })]);
|
|
58177
|
+
var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status: literal("saved") }), object({
|
|
58178
|
+
status: literal("refused"),
|
|
58179
|
+
reason: _enum(["unknown-template", "not-a-media-player"]),
|
|
58180
|
+
detail: string()
|
|
58181
|
+
})]);
|
|
58182
|
+
var deviceInput = object({ deviceId: number().int().nonnegative() });
|
|
58183
|
+
DeviceType.MediaPlayer;
|
|
58184
|
+
method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
|
|
58185
|
+
kind: "mutation",
|
|
58186
|
+
auth: "admin"
|
|
58187
|
+
}), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
|
|
58188
|
+
role: RemoteRoleSchema,
|
|
58189
|
+
/** Sends in a row (volume steps). */
|
|
58190
|
+
repeat: number().int().min(1).max(50).default(1)
|
|
58191
|
+
}), RemoteSendResultSchema, {
|
|
58192
|
+
kind: "mutation",
|
|
58193
|
+
auth: "protected"
|
|
58194
|
+
}), method(deviceInput.extend({
|
|
58195
|
+
command: RemoteMediaCommandSchema,
|
|
58196
|
+
muted: boolean().optional(),
|
|
58197
|
+
source: string().optional(),
|
|
58198
|
+
repeat: number().int().min(1).max(50).default(1)
|
|
58199
|
+
}), RemoteMediaCommandResultSchema, {
|
|
58200
|
+
kind: "mutation",
|
|
58201
|
+
auth: "protected"
|
|
58202
|
+
});
|
|
58203
|
+
var TemplateKindSchema = _enum(["remote"]);
|
|
58204
|
+
/**
|
|
58205
|
+
* template — the generic store of reusable, named operator data (D963). A
|
|
58206
|
+
* record is `{ id, kind, name, payload }`; the kinds (today only `remote`, the
|
|
58207
|
+
* button grid of a remote) and the schema each payload must satisfy are
|
|
58208
|
+
* declared by the system in `template-kinds.ts`. Nothing here is specific to a
|
|
58209
|
+
* kind: the engine validates a payload against its kind's schema and, on a
|
|
58210
|
+
* delete, asks the kind's owner whether anything still points at the record.
|
|
58211
|
+
*
|
|
58212
|
+
* Every refusal is a typed result — a UI says "unknown kind" or names the
|
|
58213
|
+
* devices that still use a template, without parsing text.
|
|
58214
|
+
*/
|
|
58215
|
+
var TemplateRecordSchema = object({
|
|
58216
|
+
id: string().min(1),
|
|
58217
|
+
kind: TemplateKindSchema,
|
|
58218
|
+
name: string().min(1).max(120),
|
|
58219
|
+
/** Shaped by the kind; `checkTemplatePayload(kind, payload)` reads it. */
|
|
58220
|
+
payload: unknown(),
|
|
58221
|
+
createdAt: number(),
|
|
58222
|
+
updatedAt: number()
|
|
58223
|
+
});
|
|
58224
|
+
var TemplateWriteResultSchema = discriminatedUnion("status", [object({
|
|
58225
|
+
status: literal("saved"),
|
|
58226
|
+
template: TemplateRecordSchema
|
|
58227
|
+
}), object({
|
|
58228
|
+
status: literal("refused"),
|
|
58229
|
+
reason: _enum(["invalid-payload", "not-found"]),
|
|
58230
|
+
detail: string()
|
|
58231
|
+
})]);
|
|
58232
|
+
/** A device still pointing at a template. */
|
|
58233
|
+
var TemplateUserSchema = object({
|
|
58234
|
+
deviceId: number().int().nonnegative(),
|
|
58235
|
+
name: string()
|
|
58236
|
+
});
|
|
58237
|
+
var TemplateDeleteResultSchema = discriminatedUnion("status", [
|
|
58238
|
+
object({ status: literal("deleted") }),
|
|
58239
|
+
object({ status: literal("not-found") }),
|
|
58240
|
+
object({
|
|
58241
|
+
status: literal("in-use"),
|
|
58242
|
+
devices: array(TemplateUserSchema).min(1)
|
|
58243
|
+
})
|
|
58244
|
+
]);
|
|
58245
|
+
method(object({ kind: TemplateKindSchema.optional() }), array(TemplateRecordSchema), { auth: "protected" }), method(object({ id: string().min(1) }), TemplateRecordSchema.nullable(), { auth: "protected" }), method(object({
|
|
58246
|
+
kind: TemplateKindSchema,
|
|
58247
|
+
name: string().min(1).max(120),
|
|
58248
|
+
payload: unknown()
|
|
58249
|
+
}), TemplateWriteResultSchema, {
|
|
58250
|
+
kind: "mutation",
|
|
58251
|
+
auth: "admin"
|
|
58252
|
+
}), method(object({
|
|
58253
|
+
id: string().min(1),
|
|
58254
|
+
name: string().min(1).max(120).optional(),
|
|
58255
|
+
payload: unknown().optional()
|
|
58256
|
+
}), TemplateWriteResultSchema, {
|
|
58257
|
+
kind: "mutation",
|
|
58258
|
+
auth: "admin"
|
|
58259
|
+
}), method(object({ id: string().min(1) }), TemplateDeleteResultSchema, {
|
|
58260
|
+
kind: "mutation",
|
|
58261
|
+
auth: "admin"
|
|
58262
|
+
});
|
|
57214
58263
|
DeviceType.Button, method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
57215
58264
|
kind: "mutation",
|
|
57216
58265
|
auth: "protected"
|
|
57217
58266
|
});
|
|
57218
58267
|
/**
|
|
58268
|
+
* A pulse train in signed microseconds: mark (+) first, then space (-), strictly
|
|
58269
|
+
* alternating, no zeros, 2..1024 entries.
|
|
58270
|
+
*/
|
|
58271
|
+
var IrTimingsSchema = array(number().int()).min(2).max(1024).superRefine((timings, ctx) => {
|
|
58272
|
+
timings.forEach((value, index) => {
|
|
58273
|
+
const expectMark = index % 2 === 0;
|
|
58274
|
+
if (value === 0 || value > 0 !== expectMark) ctx.addIssue({
|
|
58275
|
+
code: "custom",
|
|
58276
|
+
message: `timing ${index} must be a non-zero ${expectMark ? "mark (positive)" : "space (negative)"}`,
|
|
58277
|
+
path: [index]
|
|
58278
|
+
});
|
|
58279
|
+
});
|
|
58280
|
+
});
|
|
58281
|
+
/** Per-command transmit options. Every key is optional; a transmitter applies what it can. */
|
|
58282
|
+
var TransmitSettingsSchema = object({
|
|
58283
|
+
carrierHz: number().int().positive().optional(),
|
|
58284
|
+
dutyCyclePercent: number().int().min(1).max(100).optional(),
|
|
58285
|
+
repeat: number().int().min(0).max(20).optional(),
|
|
58286
|
+
repeatDelayMs: number().int().min(0).optional()
|
|
58287
|
+
});
|
|
58288
|
+
/** The setting keys a transmitter may declare as settable (`getInfo.settable`). */
|
|
58289
|
+
var TransmitSettingKeySchema = _enum([
|
|
58290
|
+
"carrierHz",
|
|
58291
|
+
"dutyCyclePercent",
|
|
58292
|
+
"repeat",
|
|
58293
|
+
"repeatDelayMs"
|
|
58294
|
+
]);
|
|
58295
|
+
var IrMediumSchema = _enum(["ir", "rf"]);
|
|
58296
|
+
var IrSendResultSchema = object({
|
|
58297
|
+
ok: literal(true),
|
|
58298
|
+
/** Settings the transmitter could not apply; the train was still sent. */
|
|
58299
|
+
ignoredSettings: array(string())
|
|
58300
|
+
});
|
|
58301
|
+
var IrTransmitterInfoSchema = object({
|
|
58302
|
+
media: array(IrMediumSchema),
|
|
58303
|
+
settable: array(TransmitSettingKeySchema),
|
|
58304
|
+
maxTimings: number().int().positive()
|
|
58305
|
+
});
|
|
58306
|
+
DeviceType.Generic, method(object({
|
|
58307
|
+
deviceId: number().int().nonnegative(),
|
|
58308
|
+
timings: IrTimingsSchema,
|
|
58309
|
+
settings: TransmitSettingsSchema.optional()
|
|
58310
|
+
}), IrSendResultSchema, {
|
|
58311
|
+
kind: "mutation",
|
|
58312
|
+
auth: "protected"
|
|
58313
|
+
}), method(object({ deviceId: number().int().nonnegative() }), IrTransmitterInfoSchema, {
|
|
58314
|
+
kind: "query",
|
|
58315
|
+
auth: "protected"
|
|
58316
|
+
});
|
|
58317
|
+
/**
|
|
57219
58318
|
* `calendar-source` — collection cap exposing per-provider calendars and
|
|
57220
58319
|
* their events. Every addon that contributes calendars (Home Assistant,
|
|
57221
58320
|
* a future Google Calendar addon, …) registers a provider here. The hub
|
|
@@ -57719,11 +58818,11 @@ var ColorInputSchema = discriminatedUnion("mode", [
|
|
|
57719
58818
|
}),
|
|
57720
58819
|
object({
|
|
57721
58820
|
mode: literal("mired"),
|
|
57722
|
-
|
|
58821
|
+
colorTemperature: number().int().min(50).max(1e3)
|
|
57723
58822
|
})
|
|
57724
58823
|
]);
|
|
57725
58824
|
object({
|
|
57726
|
-
/** Active color mode — which of `rgb` / `hsv` / `
|
|
58825
|
+
/** Active color mode — which of `rgb` / `hsv` / `colorTemperature` reflects
|
|
57727
58826
|
* the bulb's current state. */
|
|
57728
58827
|
mode: _enum([
|
|
57729
58828
|
"rgb",
|
|
@@ -57735,7 +58834,7 @@ object({
|
|
|
57735
58834
|
/** Populated when `mode === 'hsv'`. */
|
|
57736
58835
|
hsv: HsvTripletSchema.optional(),
|
|
57737
58836
|
/** Populated when `mode === 'mired'`. */
|
|
57738
|
-
|
|
58837
|
+
colorTemperature: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57739
58838
|
/** Ms epoch of the last operator-driven change. */
|
|
57740
58839
|
lastChangedAt: number()
|
|
57741
58840
|
});
|
|
@@ -57754,7 +58853,7 @@ DeviceType.Light, method(object({
|
|
|
57754
58853
|
]),
|
|
57755
58854
|
rgb: RgbTripletSchema.optional(),
|
|
57756
58855
|
hsv: HsvTripletSchema.optional(),
|
|
57757
|
-
|
|
58856
|
+
colorTemperature: number().int().optional(),
|
|
57758
58857
|
lastChangedAt: number()
|
|
57759
58858
|
});
|
|
57760
58859
|
var ConnectionTestOutcomeSchema = discriminatedUnion("outcome", [
|
|
@@ -58180,11 +59279,11 @@ object({
|
|
|
58180
59279
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
58181
59280
|
availablePrograms: array(string()),
|
|
58182
59281
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
58183
|
-
|
|
59282
|
+
remaining: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58184
59283
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
58185
|
-
|
|
59284
|
+
delayedStart: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58186
59285
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
58187
|
-
|
|
59286
|
+
progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58188
59287
|
/** True when the door is reported open; null when the door state is not known. */
|
|
58189
59288
|
doorOpen: boolean().nullable(),
|
|
58190
59289
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -58229,7 +59328,7 @@ object({
|
|
|
58229
59328
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
58230
59329
|
lastFetchedAt: number()
|
|
58231
59330
|
});
|
|
58232
|
-
var DeviceIdSchema = number().int().nonnegative();
|
|
59331
|
+
var DeviceIdSchema$1 = number().int().nonnegative();
|
|
58233
59332
|
/** A value a program option or setting can take. */
|
|
58234
59333
|
var DishwasherValueSchema = union([
|
|
58235
59334
|
boolean(),
|
|
@@ -58293,77 +59392,77 @@ var DishwasherOptionsSchema = object({
|
|
|
58293
59392
|
options: array(DishwasherOptionDescriptorSchema)
|
|
58294
59393
|
});
|
|
58295
59394
|
DeviceType.Dishwasher, method(object({
|
|
58296
|
-
deviceId: DeviceIdSchema,
|
|
59395
|
+
deviceId: DeviceIdSchema$1,
|
|
58297
59396
|
program: string().min(1).optional(),
|
|
58298
59397
|
options: record(string(), DishwasherValueSchema).optional()
|
|
58299
59398
|
}), _void(), {
|
|
58300
59399
|
kind: "mutation",
|
|
58301
59400
|
auth: "protected"
|
|
58302
|
-
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
59401
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
58303
59402
|
kind: "mutation",
|
|
58304
59403
|
auth: "protected"
|
|
58305
|
-
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
59404
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
58306
59405
|
kind: "mutation",
|
|
58307
59406
|
auth: "protected"
|
|
58308
|
-
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
59407
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
58309
59408
|
kind: "mutation",
|
|
58310
59409
|
auth: "protected"
|
|
58311
59410
|
}), method(object({
|
|
58312
|
-
deviceId: DeviceIdSchema,
|
|
59411
|
+
deviceId: DeviceIdSchema$1,
|
|
58313
59412
|
program: string().min(1)
|
|
58314
59413
|
}), _void(), {
|
|
58315
59414
|
kind: "mutation",
|
|
58316
59415
|
auth: "protected"
|
|
58317
59416
|
}), method(object({
|
|
58318
|
-
deviceId: DeviceIdSchema,
|
|
59417
|
+
deviceId: DeviceIdSchema$1,
|
|
58319
59418
|
on: boolean()
|
|
58320
59419
|
}), _void(), {
|
|
58321
59420
|
kind: "mutation",
|
|
58322
59421
|
auth: "protected"
|
|
58323
59422
|
}), method(object({
|
|
58324
|
-
deviceId: DeviceIdSchema,
|
|
59423
|
+
deviceId: DeviceIdSchema$1,
|
|
58325
59424
|
on: boolean()
|
|
58326
59425
|
}), _void(), {
|
|
58327
59426
|
kind: "mutation",
|
|
58328
59427
|
auth: "protected"
|
|
58329
59428
|
}), method(object({
|
|
58330
|
-
deviceId: DeviceIdSchema,
|
|
59429
|
+
deviceId: DeviceIdSchema$1,
|
|
58331
59430
|
on: boolean()
|
|
58332
59431
|
}), _void(), {
|
|
58333
59432
|
kind: "mutation",
|
|
58334
59433
|
auth: "protected"
|
|
58335
59434
|
}), method(object({
|
|
58336
|
-
deviceId: DeviceIdSchema,
|
|
59435
|
+
deviceId: DeviceIdSchema$1,
|
|
58337
59436
|
on: boolean()
|
|
58338
59437
|
}), _void(), {
|
|
58339
59438
|
kind: "mutation",
|
|
58340
59439
|
auth: "protected"
|
|
58341
59440
|
}), method(object({
|
|
58342
|
-
deviceId: DeviceIdSchema,
|
|
59441
|
+
deviceId: DeviceIdSchema$1,
|
|
58343
59442
|
on: boolean()
|
|
58344
59443
|
}), _void(), {
|
|
58345
59444
|
kind: "mutation",
|
|
58346
59445
|
auth: "protected"
|
|
58347
59446
|
}), method(object({
|
|
58348
|
-
deviceId: DeviceIdSchema,
|
|
59447
|
+
deviceId: DeviceIdSchema$1,
|
|
58349
59448
|
on: boolean()
|
|
58350
59449
|
}), _void(), {
|
|
58351
59450
|
kind: "mutation",
|
|
58352
59451
|
auth: "protected"
|
|
58353
59452
|
}), method(object({
|
|
58354
|
-
deviceId: DeviceIdSchema,
|
|
59453
|
+
deviceId: DeviceIdSchema$1,
|
|
58355
59454
|
on: boolean()
|
|
58356
59455
|
}), _void(), {
|
|
58357
59456
|
kind: "mutation",
|
|
58358
59457
|
auth: "protected"
|
|
58359
59458
|
}), method(object({
|
|
58360
|
-
deviceId: DeviceIdSchema,
|
|
59459
|
+
deviceId: DeviceIdSchema$1,
|
|
58361
59460
|
key: string().min(1),
|
|
58362
59461
|
value: DishwasherValueSchema
|
|
58363
59462
|
}), _void(), {
|
|
58364
59463
|
kind: "mutation",
|
|
58365
59464
|
auth: "protected"
|
|
58366
|
-
}), method(object({ deviceId: DeviceIdSchema }), DishwasherOptionsSchema, { auth: "protected" });
|
|
59465
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), DishwasherOptionsSchema, { auth: "protected" });
|
|
58367
59466
|
DeviceType.Camera;
|
|
58368
59467
|
object({
|
|
58369
59468
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
@@ -58802,7 +59901,7 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
58802
59901
|
object({
|
|
58803
59902
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
58804
59903
|
* speed surface (single-speed fan). */
|
|
58805
|
-
|
|
59904
|
+
speed: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58806
59905
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
58807
59906
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
58808
59907
|
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
@@ -58822,7 +59921,7 @@ object({
|
|
|
58822
59921
|
});
|
|
58823
59922
|
DeviceType.Fan, method(object({
|
|
58824
59923
|
deviceId: number().int().nonnegative(),
|
|
58825
|
-
|
|
59924
|
+
speed: number().min(0).max(100)
|
|
58826
59925
|
}), _void(), {
|
|
58827
59926
|
kind: "mutation",
|
|
58828
59927
|
auth: "protected"
|
|
@@ -59005,7 +60104,7 @@ DeviceType.Humidifier, method(object({
|
|
|
59005
60104
|
});
|
|
59006
60105
|
object({
|
|
59007
60106
|
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
59008
|
-
|
|
60107
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
59009
60108
|
precision: 0,
|
|
59010
60109
|
label: "Humidity"
|
|
59011
60110
|
})),
|
|
@@ -59448,7 +60547,7 @@ object({
|
|
|
59448
60547
|
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59449
60548
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
59450
60549
|
* task is active / progress is unavailable. */
|
|
59451
|
-
|
|
60550
|
+
progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59452
60551
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
59453
60552
|
* or null when unknown. */
|
|
59454
60553
|
currentCode: number().nullable().meta(readingMeta("none")),
|
|
@@ -59920,9 +61019,35 @@ var MediaInfoSchema = object({
|
|
|
59920
61019
|
/** Optional cover-art / thumbnail URL. */
|
|
59921
61020
|
imageUrl: string().optional()
|
|
59922
61021
|
});
|
|
61022
|
+
/**
|
|
61023
|
+
* Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
|
|
61024
|
+
* the device said so. `assumed`: the driver has no feedback (infrared) and
|
|
61025
|
+
* tracks what it last SENT; it moves only after a send was accepted, and a
|
|
61026
|
+
* human at the real remote makes it wrong. A UI shows an assumed value as a
|
|
61027
|
+
* guess, never as a reading.
|
|
61028
|
+
*/
|
|
61029
|
+
var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
|
|
61030
|
+
/** The fields of a media-player status a driver can only guess. */
|
|
61031
|
+
var MediaPlayerAssumedFieldSchema = _enum([
|
|
61032
|
+
"state",
|
|
61033
|
+
"volumeLevel",
|
|
61034
|
+
"isMuted",
|
|
61035
|
+
"source"
|
|
61036
|
+
]);
|
|
59923
61037
|
object({
|
|
59924
61038
|
/** Playback lifecycle state. */
|
|
59925
61039
|
state: MediaPlayerStateSchema,
|
|
61040
|
+
/**
|
|
61041
|
+
* Whether the state fields are readings or the driver's own bookkeeping.
|
|
61042
|
+
* A slice written before this field existed parses as `reported`.
|
|
61043
|
+
*/
|
|
61044
|
+
stateSource: MediaPlayerStateSourceSchema.default("reported"),
|
|
61045
|
+
/**
|
|
61046
|
+
* Which fields are the driver's own guess. `stateSource` is `assumed` when
|
|
61047
|
+
* this is not empty; a field not listed here is a reading even then (power
|
|
61048
|
+
* from a running-state source, mute guessed from the last send).
|
|
61049
|
+
*/
|
|
61050
|
+
assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
|
|
59926
61051
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
59927
61052
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
59928
61053
|
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
@@ -59938,10 +61063,10 @@ object({
|
|
|
59938
61063
|
currentMedia: MediaInfoSchema.nullable(),
|
|
59939
61064
|
/** Current playback position in ms. Null when not seekable or
|
|
59940
61065
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
59941
|
-
|
|
61066
|
+
position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59942
61067
|
/** Total duration of the current media in ms. Null when unknown
|
|
59943
61068
|
* (live stream) or nothing is playing. */
|
|
59944
|
-
|
|
61069
|
+
duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59945
61070
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
59946
61071
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
59947
61072
|
shuffle: boolean().nullable(),
|
|
@@ -59968,7 +61093,7 @@ DeviceType.MediaPlayer, method(object({ deviceId: number().int().nonnegative() }
|
|
|
59968
61093
|
auth: "protected"
|
|
59969
61094
|
}), method(object({
|
|
59970
61095
|
deviceId: number().int().nonnegative(),
|
|
59971
|
-
|
|
61096
|
+
position: number().int().nonnegative()
|
|
59972
61097
|
}), _void(), {
|
|
59973
61098
|
kind: "mutation",
|
|
59974
61099
|
auth: "protected"
|
|
@@ -60641,9 +61766,9 @@ var NetworkLinkStatusSchema = object({
|
|
|
60641
61766
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
60642
61767
|
* SKIP a null rather than coerce it.
|
|
60643
61768
|
*/
|
|
60644
|
-
|
|
61769
|
+
signal: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60645
61770
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
60646
|
-
|
|
61771
|
+
rssi: number().optional().meta(readingMeta("signal-level")),
|
|
60647
61772
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
60648
61773
|
ssid: string().optional(),
|
|
60649
61774
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
@@ -60775,7 +61900,8 @@ var TopologyNodeSchema = object({
|
|
|
60775
61900
|
isHub: boolean(),
|
|
60776
61901
|
isOnline: boolean(),
|
|
60777
61902
|
cpuPercent: number(),
|
|
60778
|
-
|
|
61903
|
+
/** `null` when the node's memory read failed or it has not reported one (D393). */
|
|
61904
|
+
memoryPercent: number().nullable(),
|
|
60779
61905
|
uptime: number(),
|
|
60780
61906
|
lastSeen: string(),
|
|
60781
61907
|
localIps: array(string()).readonly(),
|
|
@@ -61304,10 +62430,21 @@ var PetFeederDeviceStatusSchema = _enum([
|
|
|
61304
62430
|
]);
|
|
61305
62431
|
var gramsPortion = number().int().min(4).max(200);
|
|
61306
62432
|
object({
|
|
61307
|
-
/** Food
|
|
61308
|
-
*
|
|
61309
|
-
* bowl
|
|
62433
|
+
/** Food in the TANK (hopper), as the feeder's own sensor reports it
|
|
62434
|
+
* (`state.food`). A coarse level code, not grams — `0` is empty. The
|
|
62435
|
+
* amount in the bowl is `bowlFood`. On dual-hopper models this is the
|
|
62436
|
+
* combined reading; per-hopper levels live in `food1`/`food2`. Null when
|
|
62437
|
+
* the device has not reported yet. */
|
|
61310
62438
|
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
62439
|
+
/** Food in the BOWL, a mass (stored in kilograms, D944). Reported only by a
|
|
62440
|
+
* feeder with a bowl scale; null when the model has none or its reading is
|
|
62441
|
+
* of an unproven unit. */
|
|
62442
|
+
bowlFood: number().nullable().meta(readingMeta("mass")),
|
|
62443
|
+
/** True while the pet is eating (`state.eating`). */
|
|
62444
|
+
eating: boolean(),
|
|
62445
|
+
/** Whether `markFoodReplenished` does anything on this model. When false
|
|
62446
|
+
* the client must not offer it. */
|
|
62447
|
+
supportsMarkRefilled: boolean(),
|
|
61311
62448
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
61312
62449
|
* single-hopper models. */
|
|
61313
62450
|
food1: number().nullable().meta(readingMeta("none")),
|
|
@@ -61315,12 +62452,17 @@ object({
|
|
|
61315
62452
|
* single-hopper models. */
|
|
61316
62453
|
food2: number().nullable().meta(readingMeta("none")),
|
|
61317
62454
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
61318
|
-
* (`device_class: problem`, on = low). True when the
|
|
61319
|
-
*
|
|
62455
|
+
* (`device_class: problem`, on = low). True when the tank reports empty,
|
|
62456
|
+
* or, on a dual-hopper model, when EITHER hopper is empty. */
|
|
61320
62457
|
lowFood: boolean(),
|
|
61321
|
-
/** Battery charge 0..100 (%).
|
|
61322
|
-
*
|
|
62458
|
+
/** Battery charge 0..100 (%). On a feeder running on `mains` this is the
|
|
62459
|
+
* BACKUP battery's charge, not the power source. Null when the device has
|
|
62460
|
+
* no battery reading. */
|
|
61323
62461
|
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62462
|
+
/** What the feeder is powered from right now: `mains` (plugged in, the
|
|
62463
|
+
* battery is only a backup) or `battery`. Null when the device does not
|
|
62464
|
+
* report it. */
|
|
62465
|
+
powerSource: _enum(["mains", "battery"]).nullable(),
|
|
61324
62466
|
/**
|
|
61325
62467
|
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
61326
62468
|
* Providers convert from the days the feeder reports. Null when the
|
|
@@ -61348,6 +62490,14 @@ object({
|
|
|
61348
62490
|
feedSound: boolean(),
|
|
61349
62491
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
61350
62492
|
volume: number().meta(readingMeta("none")),
|
|
62493
|
+
/** Portion (grams) of the last manual feed sent from a single-hopper
|
|
62494
|
+
* stepper — the default the next manual feed starts from. Persisted per
|
|
62495
|
+
* device by the provider; null until a manual feed has been sent. */
|
|
62496
|
+
lastFeedGrams: gramsPortion.nullable(),
|
|
62497
|
+
/** Hopper-1 portion of the last manual feed (dual-hopper); null until sent. */
|
|
62498
|
+
lastFeedHopper1: gramsPortion.nullable(),
|
|
62499
|
+
/** Hopper-2 portion of the last manual feed (dual-hopper); null until sent. */
|
|
62500
|
+
lastFeedHopper2: gramsPortion.nullable(),
|
|
61351
62501
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
61352
62502
|
lastFetchedAt: number()
|
|
61353
62503
|
});
|
|
@@ -61402,6 +62552,64 @@ DeviceType.PetFeeder, method(object({
|
|
|
61402
62552
|
kind: "mutation",
|
|
61403
62553
|
auth: "protected"
|
|
61404
62554
|
});
|
|
62555
|
+
object({
|
|
62556
|
+
/** Water in the tank, 0..100 (%). Null while the source has not reported. */
|
|
62557
|
+
waterLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62558
|
+
/** Water in the tank, in litres. Null while the source has not reported. */
|
|
62559
|
+
waterVolume: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62560
|
+
/** True when the tank is empty. Null while unknown. */
|
|
62561
|
+
empty: boolean().nullable(),
|
|
62562
|
+
/** True while the pump is running. Null while unknown. */
|
|
62563
|
+
pumpRunning: boolean().nullable(),
|
|
62564
|
+
/** True when the pump works on an on/off duty cycle rather than continuously. */
|
|
62565
|
+
pumpIntervalEnabled: boolean().nullable(),
|
|
62566
|
+
/** How long the pump runs per cycle, in seconds. */
|
|
62567
|
+
pumpOnTime: number().min(0).nullable().meta(readingMeta("duration")),
|
|
62568
|
+
/** How long the pump rests per cycle, in seconds. */
|
|
62569
|
+
pumpOffTime: number().min(0).nullable().meta(readingMeta("duration")),
|
|
62570
|
+
/** Water drunk in the last drink, in litres. */
|
|
62571
|
+
lastDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62572
|
+
/** Water drunk in the current hour, in litres. */
|
|
62573
|
+
currentHourDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62574
|
+
/** Water drunk over the last 24 hours (rolling), in litres. */
|
|
62575
|
+
last24hDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62576
|
+
/** Water drunk since local midnight, in litres. */
|
|
62577
|
+
todayDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62578
|
+
/** Decoded fault message. Null means healthy; a non-null string is an active fault. */
|
|
62579
|
+
error: string().nullable(),
|
|
62580
|
+
/** Ms epoch when the slice was last refreshed. */
|
|
62581
|
+
lastFetchedAt: number()
|
|
62582
|
+
});
|
|
62583
|
+
var DeviceIdSchema = number().int().nonnegative();
|
|
62584
|
+
var MinutesSchema = number().int().min(0);
|
|
62585
|
+
DeviceType.PetFountain, method(object({
|
|
62586
|
+
deviceId: DeviceIdSchema,
|
|
62587
|
+
on: boolean()
|
|
62588
|
+
}), _void(), {
|
|
62589
|
+
kind: "mutation",
|
|
62590
|
+
auth: "protected"
|
|
62591
|
+
}), method(object({
|
|
62592
|
+
deviceId: DeviceIdSchema,
|
|
62593
|
+
on: boolean()
|
|
62594
|
+
}), _void(), {
|
|
62595
|
+
kind: "mutation",
|
|
62596
|
+
auth: "protected"
|
|
62597
|
+
}), method(object({
|
|
62598
|
+
deviceId: DeviceIdSchema,
|
|
62599
|
+
minutes: MinutesSchema
|
|
62600
|
+
}), _void(), {
|
|
62601
|
+
kind: "mutation",
|
|
62602
|
+
auth: "protected"
|
|
62603
|
+
}), method(object({
|
|
62604
|
+
deviceId: DeviceIdSchema,
|
|
62605
|
+
minutes: MinutesSchema
|
|
62606
|
+
}), _void(), {
|
|
62607
|
+
kind: "mutation",
|
|
62608
|
+
auth: "protected"
|
|
62609
|
+
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
62610
|
+
kind: "mutation",
|
|
62611
|
+
auth: "protected"
|
|
62612
|
+
});
|
|
61405
62613
|
var VehicleSchema = object({
|
|
61406
62614
|
id: string(),
|
|
61407
62615
|
name: string(),
|
|
@@ -61783,16 +62991,16 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
61783
62991
|
auth: "admin"
|
|
61784
62992
|
});
|
|
61785
62993
|
object({
|
|
61786
|
-
/** Instantaneous power draw
|
|
61787
|
-
|
|
62994
|
+
/** Instantaneous power draw (watts). */
|
|
62995
|
+
power: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
61788
62996
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
61789
|
-
|
|
61790
|
-
/** Voltage
|
|
61791
|
-
|
|
62997
|
+
energy: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
62998
|
+
/** Voltage (volts). */
|
|
62999
|
+
voltage: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
61792
63000
|
/** Current in amperes. */
|
|
61793
|
-
|
|
63001
|
+
current: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
61794
63002
|
/** Apparent power in volt-amperes. */
|
|
61795
|
-
|
|
63003
|
+
apparentPower: number().optional().meta(readingMeta("apparent-power")),
|
|
61796
63004
|
/** Power factor (0..1) if reported. */
|
|
61797
63005
|
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
61798
63006
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -61847,16 +63055,13 @@ object({
|
|
|
61847
63055
|
location: string().nullable(),
|
|
61848
63056
|
/** GPS coordinates when available. Null otherwise. */
|
|
61849
63057
|
gps: GpsLocationSchema.nullable(),
|
|
61850
|
-
/** Optional battery level of the tracking device (0..100). Null
|
|
61851
|
-
* when not reported. */
|
|
61852
|
-
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61853
63058
|
/** Ms epoch when the slice was last updated. */
|
|
61854
63059
|
lastChangedAt: number()
|
|
61855
63060
|
});
|
|
61856
63061
|
DeviceType.Presence;
|
|
61857
63062
|
object({
|
|
61858
63063
|
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
61859
|
-
|
|
63064
|
+
pressure: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
61860
63065
|
/** Ms epoch when the slice was last updated. */
|
|
61861
63066
|
lastFetchedAt: number()
|
|
61862
63067
|
});
|
|
@@ -64859,7 +66064,7 @@ object({
|
|
|
64859
66064
|
DeviceType.Sensor;
|
|
64860
66065
|
object({
|
|
64861
66066
|
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
64862
|
-
|
|
66067
|
+
temperature: number().nullable().meta(readingMeta("temperature", {
|
|
64863
66068
|
precision: 1,
|
|
64864
66069
|
label: "Temperature"
|
|
64865
66070
|
})),
|
|
@@ -65123,7 +66328,7 @@ object({
|
|
|
65123
66328
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
65124
66329
|
availableFanSpeeds: array(string()),
|
|
65125
66330
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
65126
|
-
|
|
66331
|
+
progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
65127
66332
|
/** Current error code (0 / null = no error). */
|
|
65128
66333
|
errorCode: number().nullable().meta(readingMeta("none")),
|
|
65129
66334
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
@@ -65992,9 +67197,17 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
65992
67197
|
kind: "mutation",
|
|
65993
67198
|
auth: "admin"
|
|
65994
67199
|
});
|
|
67200
|
+
discriminatedUnion("kind", [object({
|
|
67201
|
+
kind: literal("raw"),
|
|
67202
|
+
timings: array(number().int()),
|
|
67203
|
+
settings: TransmitSettingsSchema.optional()
|
|
67204
|
+
}), object({
|
|
67205
|
+
kind: literal("pronto"),
|
|
67206
|
+
code: string()
|
|
67207
|
+
})]);
|
|
65995
67208
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
65996
67209
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
65997
|
-
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;
|
|
67210
|
+
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.PetFountain, 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.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
65998
67211
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
65999
67212
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
66000
67213
|
new Set(CAP_NAMES);
|
|
@@ -66047,7 +67260,7 @@ var AccessoryKind = {
|
|
|
66047
67260
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
66048
67261
|
};
|
|
66049
67262
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
66050
|
-
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, 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;
|
|
67263
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer;
|
|
66051
67264
|
new Set(Object.values(DeviceType));
|
|
66052
67265
|
Object.freeze({
|
|
66053
67266
|
"accessories.getStatus": {
|
|
@@ -66064,6 +67277,104 @@ Object.freeze({
|
|
|
66064
67277
|
access: "create",
|
|
66065
67278
|
role: "admin"
|
|
66066
67279
|
},
|
|
67280
|
+
"actions.create": {
|
|
67281
|
+
capName: "actions",
|
|
67282
|
+
capScope: "system",
|
|
67283
|
+
addonId: null,
|
|
67284
|
+
access: "create",
|
|
67285
|
+
role: "admin"
|
|
67286
|
+
},
|
|
67287
|
+
"actions.delete": {
|
|
67288
|
+
capName: "actions",
|
|
67289
|
+
capScope: "system",
|
|
67290
|
+
addonId: null,
|
|
67291
|
+
access: "delete",
|
|
67292
|
+
role: "admin"
|
|
67293
|
+
},
|
|
67294
|
+
"actions.get": {
|
|
67295
|
+
capName: "actions",
|
|
67296
|
+
capScope: "system",
|
|
67297
|
+
addonId: null,
|
|
67298
|
+
access: "view",
|
|
67299
|
+
role: "viewer"
|
|
67300
|
+
},
|
|
67301
|
+
"actions.getLinks": {
|
|
67302
|
+
capName: "actions",
|
|
67303
|
+
capScope: "system",
|
|
67304
|
+
addonId: null,
|
|
67305
|
+
access: "view",
|
|
67306
|
+
role: "admin"
|
|
67307
|
+
},
|
|
67308
|
+
"actions.getTraces": {
|
|
67309
|
+
capName: "actions",
|
|
67310
|
+
capScope: "system",
|
|
67311
|
+
addonId: null,
|
|
67312
|
+
access: "view",
|
|
67313
|
+
role: "admin"
|
|
67314
|
+
},
|
|
67315
|
+
"actions.list": {
|
|
67316
|
+
capName: "actions",
|
|
67317
|
+
capScope: "system",
|
|
67318
|
+
addonId: null,
|
|
67319
|
+
access: "view",
|
|
67320
|
+
role: "admin"
|
|
67321
|
+
},
|
|
67322
|
+
"actions.listForCamera": {
|
|
67323
|
+
capName: "actions",
|
|
67324
|
+
capScope: "system",
|
|
67325
|
+
addonId: null,
|
|
67326
|
+
access: "view",
|
|
67327
|
+
role: "viewer"
|
|
67328
|
+
},
|
|
67329
|
+
"actions.run": {
|
|
67330
|
+
capName: "actions",
|
|
67331
|
+
capScope: "system",
|
|
67332
|
+
addonId: null,
|
|
67333
|
+
access: "create",
|
|
67334
|
+
role: "viewer"
|
|
67335
|
+
},
|
|
67336
|
+
"actions.setLinks": {
|
|
67337
|
+
capName: "actions",
|
|
67338
|
+
capScope: "system",
|
|
67339
|
+
addonId: null,
|
|
67340
|
+
access: "create",
|
|
67341
|
+
role: "admin"
|
|
67342
|
+
},
|
|
67343
|
+
"actions.stop": {
|
|
67344
|
+
capName: "actions",
|
|
67345
|
+
capScope: "system",
|
|
67346
|
+
addonId: null,
|
|
67347
|
+
access: "create",
|
|
67348
|
+
role: "admin"
|
|
67349
|
+
},
|
|
67350
|
+
"actions.update": {
|
|
67351
|
+
capName: "actions",
|
|
67352
|
+
capScope: "system",
|
|
67353
|
+
addonId: null,
|
|
67354
|
+
access: "create",
|
|
67355
|
+
role: "admin"
|
|
67356
|
+
},
|
|
67357
|
+
"actionSource.listActions": {
|
|
67358
|
+
capName: "action-source",
|
|
67359
|
+
capScope: "system",
|
|
67360
|
+
addonId: null,
|
|
67361
|
+
access: "view",
|
|
67362
|
+
role: "admin"
|
|
67363
|
+
},
|
|
67364
|
+
"actionSource.runAction": {
|
|
67365
|
+
capName: "action-source",
|
|
67366
|
+
capScope: "system",
|
|
67367
|
+
addonId: null,
|
|
67368
|
+
access: "create",
|
|
67369
|
+
role: "admin"
|
|
67370
|
+
},
|
|
67371
|
+
"actionSource.stopAction": {
|
|
67372
|
+
capName: "action-source",
|
|
67373
|
+
capScope: "system",
|
|
67374
|
+
addonId: null,
|
|
67375
|
+
access: "create",
|
|
67376
|
+
role: "admin"
|
|
67377
|
+
},
|
|
66067
67378
|
"addonPages.listPages": {
|
|
66068
67379
|
capName: "addon-pages",
|
|
66069
67380
|
capScope: "system",
|
|
@@ -67345,6 +68656,13 @@ Object.freeze({
|
|
|
67345
68656
|
access: "view",
|
|
67346
68657
|
role: "admin"
|
|
67347
68658
|
},
|
|
68659
|
+
"coreBlocks.getAutomationRunState": {
|
|
68660
|
+
capName: "core-blocks",
|
|
68661
|
+
capScope: "system",
|
|
68662
|
+
addonId: null,
|
|
68663
|
+
access: "view",
|
|
68664
|
+
role: "admin"
|
|
68665
|
+
},
|
|
67348
68666
|
"coreBlocks.getBlockSettings": {
|
|
67349
68667
|
capName: "core-blocks",
|
|
67350
68668
|
capScope: "system",
|
|
@@ -67366,6 +68684,13 @@ Object.freeze({
|
|
|
67366
68684
|
access: "view",
|
|
67367
68685
|
role: "admin"
|
|
67368
68686
|
},
|
|
68687
|
+
"coreBlocks.getTraces": {
|
|
68688
|
+
capName: "core-blocks",
|
|
68689
|
+
capScope: "system",
|
|
68690
|
+
addonId: null,
|
|
68691
|
+
access: "view",
|
|
68692
|
+
role: "admin"
|
|
68693
|
+
},
|
|
67369
68694
|
"coreBlocks.getTypeDefs": {
|
|
67370
68695
|
capName: "core-blocks",
|
|
67371
68696
|
capScope: "system",
|
|
@@ -67401,6 +68726,13 @@ Object.freeze({
|
|
|
67401
68726
|
access: "create",
|
|
67402
68727
|
role: "admin"
|
|
67403
68728
|
},
|
|
68729
|
+
"coreBlocks.reportAutomationRun": {
|
|
68730
|
+
capName: "core-blocks",
|
|
68731
|
+
capScope: "system",
|
|
68732
|
+
addonId: null,
|
|
68733
|
+
access: "create",
|
|
68734
|
+
role: "admin"
|
|
68735
|
+
},
|
|
67404
68736
|
"coreBlocks.restart": {
|
|
67405
68737
|
capName: "core-blocks",
|
|
67406
68738
|
capScope: "system",
|
|
@@ -67863,6 +69195,13 @@ Object.freeze({
|
|
|
67863
69195
|
access: "create",
|
|
67864
69196
|
role: "admin"
|
|
67865
69197
|
},
|
|
69198
|
+
"deviceExport.exposeEntity": {
|
|
69199
|
+
capName: "device-export",
|
|
69200
|
+
capScope: "system",
|
|
69201
|
+
addonId: null,
|
|
69202
|
+
access: "create",
|
|
69203
|
+
role: "admin"
|
|
69204
|
+
},
|
|
67866
69205
|
"deviceExport.getDeviceLiveContribution": {
|
|
67867
69206
|
capName: "device-export",
|
|
67868
69207
|
capScope: "system",
|
|
@@ -67891,6 +69230,13 @@ Object.freeze({
|
|
|
67891
69230
|
access: "view",
|
|
67892
69231
|
role: "admin"
|
|
67893
69232
|
},
|
|
69233
|
+
"deviceExport.listExposedEntities": {
|
|
69234
|
+
capName: "device-export",
|
|
69235
|
+
capScope: "system",
|
|
69236
|
+
addonId: null,
|
|
69237
|
+
access: "view",
|
|
69238
|
+
role: "admin"
|
|
69239
|
+
},
|
|
67894
69240
|
"deviceExport.listSupportedDeviceKinds": {
|
|
67895
69241
|
capName: "device-export",
|
|
67896
69242
|
capScope: "system",
|
|
@@ -67898,6 +69244,13 @@ Object.freeze({
|
|
|
67898
69244
|
access: "view",
|
|
67899
69245
|
role: "admin"
|
|
67900
69246
|
},
|
|
69247
|
+
"deviceExport.listSupportedEntityKinds": {
|
|
69248
|
+
capName: "device-export",
|
|
69249
|
+
capScope: "system",
|
|
69250
|
+
addonId: null,
|
|
69251
|
+
access: "view",
|
|
69252
|
+
role: "admin"
|
|
69253
|
+
},
|
|
67901
69254
|
"deviceExport.unexposeDevice": {
|
|
67902
69255
|
capName: "device-export",
|
|
67903
69256
|
capScope: "system",
|
|
@@ -67905,6 +69258,13 @@ Object.freeze({
|
|
|
67905
69258
|
access: "create",
|
|
67906
69259
|
role: "admin"
|
|
67907
69260
|
},
|
|
69261
|
+
"deviceExport.unexposeEntity": {
|
|
69262
|
+
capName: "device-export",
|
|
69263
|
+
capScope: "system",
|
|
69264
|
+
addonId: null,
|
|
69265
|
+
access: "create",
|
|
69266
|
+
role: "admin"
|
|
69267
|
+
},
|
|
67908
69268
|
"deviceExtension.listCandidates": {
|
|
67909
69269
|
capName: "device-extension",
|
|
67910
69270
|
capScope: "device",
|
|
@@ -69480,6 +70840,20 @@ Object.freeze({
|
|
|
69480
70840
|
access: "create",
|
|
69481
70841
|
role: "viewer"
|
|
69482
70842
|
},
|
|
70843
|
+
"irTransmitter.getInfo": {
|
|
70844
|
+
capName: "ir-transmitter",
|
|
70845
|
+
capScope: "device",
|
|
70846
|
+
addonId: null,
|
|
70847
|
+
access: "view",
|
|
70848
|
+
role: "viewer"
|
|
70849
|
+
},
|
|
70850
|
+
"irTransmitter.send": {
|
|
70851
|
+
capName: "ir-transmitter",
|
|
70852
|
+
capScope: "device",
|
|
70853
|
+
addonId: null,
|
|
70854
|
+
access: "create",
|
|
70855
|
+
role: "viewer"
|
|
70856
|
+
},
|
|
69483
70857
|
"keychain.delete": {
|
|
69484
70858
|
capName: "keychain",
|
|
69485
70859
|
capScope: "system",
|
|
@@ -70712,6 +72086,13 @@ Object.freeze({
|
|
|
70712
72086
|
access: "create",
|
|
70713
72087
|
role: "admin"
|
|
70714
72088
|
},
|
|
72089
|
+
"nodeRemovalHook.onNodeRemoved": {
|
|
72090
|
+
capName: "node-removal-hook",
|
|
72091
|
+
capScope: "system",
|
|
72092
|
+
addonId: null,
|
|
72093
|
+
access: "create",
|
|
72094
|
+
role: "admin"
|
|
72095
|
+
},
|
|
70715
72096
|
"nodes.clusterAddonStatus": {
|
|
70716
72097
|
capName: "nodes",
|
|
70717
72098
|
capScope: "system",
|
|
@@ -71349,6 +72730,48 @@ Object.freeze({
|
|
|
71349
72730
|
access: "create",
|
|
71350
72731
|
role: "viewer"
|
|
71351
72732
|
},
|
|
72733
|
+
"petFountain.getStatus": {
|
|
72734
|
+
capName: "pet-fountain",
|
|
72735
|
+
capScope: "device",
|
|
72736
|
+
addonId: null,
|
|
72737
|
+
access: "view",
|
|
72738
|
+
role: "viewer"
|
|
72739
|
+
},
|
|
72740
|
+
"petFountain.resetDailyConsumption": {
|
|
72741
|
+
capName: "pet-fountain",
|
|
72742
|
+
capScope: "device",
|
|
72743
|
+
addonId: null,
|
|
72744
|
+
access: "delete",
|
|
72745
|
+
role: "viewer"
|
|
72746
|
+
},
|
|
72747
|
+
"petFountain.setPump": {
|
|
72748
|
+
capName: "pet-fountain",
|
|
72749
|
+
capScope: "device",
|
|
72750
|
+
addonId: null,
|
|
72751
|
+
access: "create",
|
|
72752
|
+
role: "viewer"
|
|
72753
|
+
},
|
|
72754
|
+
"petFountain.setPumpInterval": {
|
|
72755
|
+
capName: "pet-fountain",
|
|
72756
|
+
capScope: "device",
|
|
72757
|
+
addonId: null,
|
|
72758
|
+
access: "create",
|
|
72759
|
+
role: "viewer"
|
|
72760
|
+
},
|
|
72761
|
+
"petFountain.setPumpOffMinutes": {
|
|
72762
|
+
capName: "pet-fountain",
|
|
72763
|
+
capScope: "device",
|
|
72764
|
+
addonId: null,
|
|
72765
|
+
access: "create",
|
|
72766
|
+
role: "viewer"
|
|
72767
|
+
},
|
|
72768
|
+
"petFountain.setPumpOnMinutes": {
|
|
72769
|
+
capName: "pet-fountain",
|
|
72770
|
+
capScope: "device",
|
|
72771
|
+
addonId: null,
|
|
72772
|
+
access: "create",
|
|
72773
|
+
role: "viewer"
|
|
72774
|
+
},
|
|
71352
72775
|
"pipelineAnalytics.addRetrainFrameFromRecording": {
|
|
71353
72776
|
capName: "pipeline-analytics",
|
|
71354
72777
|
capScope: "device",
|
|
@@ -73603,6 +75026,41 @@ Object.freeze({
|
|
|
73603
75026
|
access: "create",
|
|
73604
75027
|
role: "admin"
|
|
73605
75028
|
},
|
|
75029
|
+
"remote.getConfig": {
|
|
75030
|
+
capName: "remote",
|
|
75031
|
+
capScope: "system",
|
|
75032
|
+
addonId: null,
|
|
75033
|
+
access: "view",
|
|
75034
|
+
role: "admin"
|
|
75035
|
+
},
|
|
75036
|
+
"remote.listCommands": {
|
|
75037
|
+
capName: "remote",
|
|
75038
|
+
capScope: "system",
|
|
75039
|
+
addonId: null,
|
|
75040
|
+
access: "view",
|
|
75041
|
+
role: "admin"
|
|
75042
|
+
},
|
|
75043
|
+
"remote.sendCommand": {
|
|
75044
|
+
capName: "remote",
|
|
75045
|
+
capScope: "system",
|
|
75046
|
+
addonId: null,
|
|
75047
|
+
access: "create",
|
|
75048
|
+
role: "admin"
|
|
75049
|
+
},
|
|
75050
|
+
"remote.sendMediaCommand": {
|
|
75051
|
+
capName: "remote",
|
|
75052
|
+
capScope: "system",
|
|
75053
|
+
addonId: null,
|
|
75054
|
+
access: "create",
|
|
75055
|
+
role: "admin"
|
|
75056
|
+
},
|
|
75057
|
+
"remote.setConfig": {
|
|
75058
|
+
capName: "remote",
|
|
75059
|
+
capScope: "system",
|
|
75060
|
+
addonId: null,
|
|
75061
|
+
access: "create",
|
|
75062
|
+
role: "admin"
|
|
75063
|
+
},
|
|
73606
75064
|
"runningState.getStatus": {
|
|
73607
75065
|
capName: "running-state",
|
|
73608
75066
|
capScope: "device",
|
|
@@ -73715,6 +75173,13 @@ Object.freeze({
|
|
|
73715
75173
|
access: "create",
|
|
73716
75174
|
role: "admin"
|
|
73717
75175
|
},
|
|
75176
|
+
"serverManagement.getLaunchOverrides": {
|
|
75177
|
+
capName: "server-management",
|
|
75178
|
+
capScope: "system",
|
|
75179
|
+
addonId: null,
|
|
75180
|
+
access: "view",
|
|
75181
|
+
role: "admin"
|
|
75182
|
+
},
|
|
73718
75183
|
"serverManagement.getServerPackageStatus": {
|
|
73719
75184
|
capName: "server-management",
|
|
73720
75185
|
capScope: "system",
|
|
@@ -73736,6 +75201,13 @@ Object.freeze({
|
|
|
73736
75201
|
access: "create",
|
|
73737
75202
|
role: "admin"
|
|
73738
75203
|
},
|
|
75204
|
+
"serverManagement.setLaunchOverrides": {
|
|
75205
|
+
capName: "server-management",
|
|
75206
|
+
capScope: "system",
|
|
75207
|
+
addonId: null,
|
|
75208
|
+
access: "create",
|
|
75209
|
+
role: "admin"
|
|
75210
|
+
},
|
|
73739
75211
|
"settingsStore.aggregate": {
|
|
73740
75212
|
capName: "settings-store",
|
|
73741
75213
|
capScope: "system",
|
|
@@ -74793,6 +76265,41 @@ Object.freeze({
|
|
|
74793
76265
|
access: "view",
|
|
74794
76266
|
role: "viewer"
|
|
74795
76267
|
},
|
|
76268
|
+
"template.create": {
|
|
76269
|
+
capName: "template",
|
|
76270
|
+
capScope: "system",
|
|
76271
|
+
addonId: null,
|
|
76272
|
+
access: "create",
|
|
76273
|
+
role: "admin"
|
|
76274
|
+
},
|
|
76275
|
+
"template.delete": {
|
|
76276
|
+
capName: "template",
|
|
76277
|
+
capScope: "system",
|
|
76278
|
+
addonId: null,
|
|
76279
|
+
access: "delete",
|
|
76280
|
+
role: "admin"
|
|
76281
|
+
},
|
|
76282
|
+
"template.get": {
|
|
76283
|
+
capName: "template",
|
|
76284
|
+
capScope: "system",
|
|
76285
|
+
addonId: null,
|
|
76286
|
+
access: "view",
|
|
76287
|
+
role: "admin"
|
|
76288
|
+
},
|
|
76289
|
+
"template.list": {
|
|
76290
|
+
capName: "template",
|
|
76291
|
+
capScope: "system",
|
|
76292
|
+
addonId: null,
|
|
76293
|
+
access: "view",
|
|
76294
|
+
role: "admin"
|
|
76295
|
+
},
|
|
76296
|
+
"template.update": {
|
|
76297
|
+
capName: "template",
|
|
76298
|
+
capScope: "system",
|
|
76299
|
+
addonId: null,
|
|
76300
|
+
access: "create",
|
|
76301
|
+
role: "admin"
|
|
76302
|
+
},
|
|
74796
76303
|
"terminalSession.adoptLegacyMonitor": {
|
|
74797
76304
|
capName: "terminal-session",
|
|
74798
76305
|
capScope: "system",
|
|
@@ -75974,7 +77481,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
75974
77481
|
label: t("Full brightness", "Luminosità massima"),
|
|
75975
77482
|
phrase: t("Set {device} to full brightness", "Porta {device} alla massima luminosità"),
|
|
75976
77483
|
icon: "sun",
|
|
75977
|
-
args: {
|
|
77484
|
+
args: { level: 100 }
|
|
75978
77485
|
},
|
|
75979
77486
|
{
|
|
75980
77487
|
id: "brightness.half",
|
|
@@ -75982,7 +77489,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
75982
77489
|
label: t("Half brightness", "Luminosità a metà"),
|
|
75983
77490
|
phrase: t("Dim {device} to half", "Abbassa {device} a metà luminosità"),
|
|
75984
77491
|
icon: "sun-dim",
|
|
75985
|
-
args: {
|
|
77492
|
+
args: { level: 50 }
|
|
75986
77493
|
},
|
|
75987
77494
|
{
|
|
75988
77495
|
id: "brightness.off",
|
|
@@ -75990,16 +77497,16 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
75990
77497
|
label: t("Brightness off", "Luminosità a zero"),
|
|
75991
77498
|
phrase: t("Dim {device} to zero", "Abbassa {device} a zero"),
|
|
75992
77499
|
icon: "lightbulb-off",
|
|
75993
|
-
args: {
|
|
77500
|
+
args: { level: 0 }
|
|
75994
77501
|
},
|
|
75995
77502
|
{
|
|
75996
77503
|
id: "brightness.set",
|
|
75997
77504
|
method: "setBrightness",
|
|
75998
77505
|
label: t("Set brightness", "Imposta la luminosità"),
|
|
75999
|
-
phrase: t("Set the brightness of {device} to {
|
|
77506
|
+
phrase: t("Set the brightness of {device} to {level}", "Imposta la luminosità di {device} a {level}"),
|
|
76000
77507
|
icon: "sun-medium",
|
|
76001
77508
|
openArgs: [{
|
|
76002
|
-
key: "
|
|
77509
|
+
key: "level",
|
|
76003
77510
|
label: PERCENT,
|
|
76004
77511
|
offer: {
|
|
76005
77512
|
kind: "number",
|
|
@@ -76013,13 +77520,13 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
76013
77520
|
],
|
|
76014
77521
|
state: [{
|
|
76015
77522
|
kind: "numeric",
|
|
76016
|
-
field: "
|
|
77523
|
+
field: "level",
|
|
76017
77524
|
quantity: t("the brightness", "la luminosità"),
|
|
76018
77525
|
label: t("Brightness", "Luminosità"),
|
|
76019
77526
|
unit: "%",
|
|
76020
77527
|
icon: "sun"
|
|
76021
77528
|
}],
|
|
76022
|
-
events: { onBrightnessChanged: { notOperatorFacing: "the `
|
|
77529
|
+
events: { onBrightnessChanged: { notOperatorFacing: "the `level` state trigger reads the same change" } }
|
|
76023
77530
|
},
|
|
76024
77531
|
color: {
|
|
76025
77532
|
scope: "device",
|
|
@@ -76033,7 +77540,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
76033
77540
|
icon: "sun",
|
|
76034
77541
|
args: { color: {
|
|
76035
77542
|
mode: "mired",
|
|
76036
|
-
|
|
77543
|
+
colorTemperature: 370
|
|
76037
77544
|
} }
|
|
76038
77545
|
},
|
|
76039
77546
|
{
|
|
@@ -76044,7 +77551,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
76044
77551
|
icon: "snowflake",
|
|
76045
77552
|
args: { color: {
|
|
76046
77553
|
mode: "mired",
|
|
76047
|
-
|
|
77554
|
+
colorTemperature: 200
|
|
76048
77555
|
} }
|
|
76049
77556
|
},
|
|
76050
77557
|
{
|
|
@@ -76658,7 +78165,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
76658
78165
|
label: t("Fan off", "Ventilatore spento"),
|
|
76659
78166
|
phrase: t("Stop {device}", "Ferma {device}"),
|
|
76660
78167
|
icon: "power-off",
|
|
76661
|
-
args: {
|
|
78168
|
+
args: { speed: 0 }
|
|
76662
78169
|
},
|
|
76663
78170
|
{
|
|
76664
78171
|
id: "fan.full",
|
|
@@ -76666,16 +78173,16 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
76666
78173
|
label: t("Fan full", "Ventilatore al massimo"),
|
|
76667
78174
|
phrase: t("Run {device} at full speed", "Porta {device} alla massima velocità"),
|
|
76668
78175
|
icon: "fan",
|
|
76669
|
-
args: {
|
|
78176
|
+
args: { speed: 100 }
|
|
76670
78177
|
},
|
|
76671
78178
|
{
|
|
76672
78179
|
id: "fan.speed",
|
|
76673
78180
|
method: "setPercentage",
|
|
76674
78181
|
label: t("Set speed", "Imposta la velocità"),
|
|
76675
|
-
phrase: t("Set the speed of {device} to {
|
|
78182
|
+
phrase: t("Set the speed of {device} to {speed}", "Imposta la velocità di {device} al {speed}"),
|
|
76676
78183
|
icon: "fan",
|
|
76677
78184
|
openArgs: [{
|
|
76678
|
-
key: "
|
|
78185
|
+
key: "speed",
|
|
76679
78186
|
label: t("Speed", "Velocità"),
|
|
76680
78187
|
offer: {
|
|
76681
78188
|
kind: "number",
|
|
@@ -76737,7 +78244,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
76737
78244
|
],
|
|
76738
78245
|
state: [{
|
|
76739
78246
|
kind: "numeric",
|
|
76740
|
-
field: "
|
|
78247
|
+
field: "speed",
|
|
76741
78248
|
quantity: t("the speed", "la velocità"),
|
|
76742
78249
|
label: t("Speed", "Velocità"),
|
|
76743
78250
|
unit: "%",
|
|
@@ -77103,6 +78610,11 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
77103
78610
|
icon: "circle-dot"
|
|
77104
78611
|
}]
|
|
77105
78612
|
},
|
|
78613
|
+
"ir-transmitter": {
|
|
78614
|
+
scope: "device",
|
|
78615
|
+
noun: t("IR / RF transmitter", "Trasmettitore IR / RF"),
|
|
78616
|
+
notOperatorFacing: { send: "a raw pulse train is not something an operator composes in an automation; the remote that owns the command table sends it" }
|
|
78617
|
+
},
|
|
77106
78618
|
control: {
|
|
77107
78619
|
scope: "device",
|
|
77108
78620
|
noun: t("Control", "Controllo"),
|
|
@@ -77535,7 +79047,7 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
77535
79047
|
},
|
|
77536
79048
|
{
|
|
77537
79049
|
kind: "numeric",
|
|
77538
|
-
field: "
|
|
79050
|
+
field: "progress",
|
|
77539
79051
|
quantity: t("the cycle progress", "l’avanzamento del lavaggio"),
|
|
77540
79052
|
label: t("Progress", "Avanzamento"),
|
|
77541
79053
|
unit: "%",
|
|
@@ -77756,6 +79268,100 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
77756
79268
|
}
|
|
77757
79269
|
]
|
|
77758
79270
|
},
|
|
79271
|
+
"pet-fountain": {
|
|
79272
|
+
scope: "device",
|
|
79273
|
+
noun: t("Pet fountain", "Fontana per animali"),
|
|
79274
|
+
actions: [
|
|
79275
|
+
{
|
|
79276
|
+
id: "petFountain.pumpOn",
|
|
79277
|
+
method: "setPump",
|
|
79278
|
+
label: t("Pump on", "Pompa accesa"),
|
|
79279
|
+
phrase: t("Start the pump of {device}", "Avvia la pompa di {device}"),
|
|
79280
|
+
icon: "play",
|
|
79281
|
+
args: { on: true }
|
|
79282
|
+
},
|
|
79283
|
+
{
|
|
79284
|
+
id: "petFountain.pumpOff",
|
|
79285
|
+
method: "setPump",
|
|
79286
|
+
label: t("Pump off", "Pompa spenta"),
|
|
79287
|
+
phrase: t("Stop the pump of {device}", "Ferma la pompa di {device}"),
|
|
79288
|
+
icon: "square",
|
|
79289
|
+
args: { on: false }
|
|
79290
|
+
},
|
|
79291
|
+
{
|
|
79292
|
+
id: "petFountain.intervalOn",
|
|
79293
|
+
method: "setPumpInterval",
|
|
79294
|
+
label: t("Pump cycle on", "Ciclo pompa attivo"),
|
|
79295
|
+
phrase: t("Run the pump of {device} on its on/off cycle", "Fai lavorare la pompa di {device} a ciclo acceso/spento"),
|
|
79296
|
+
icon: "timer",
|
|
79297
|
+
args: { on: true }
|
|
79298
|
+
},
|
|
79299
|
+
{
|
|
79300
|
+
id: "petFountain.intervalOff",
|
|
79301
|
+
method: "setPumpInterval",
|
|
79302
|
+
label: t("Pump cycle off", "Ciclo pompa spento"),
|
|
79303
|
+
phrase: t("Run the pump of {device} continuously", "Fai lavorare la pompa di {device} in continuo"),
|
|
79304
|
+
icon: "timer-off",
|
|
79305
|
+
args: { on: false }
|
|
79306
|
+
},
|
|
79307
|
+
{
|
|
79308
|
+
id: "petFountain.pumpOnMinutes",
|
|
79309
|
+
method: "setPumpOnMinutes",
|
|
79310
|
+
label: t("Set pump run time", "Imposta il tempo di lavoro della pompa"),
|
|
79311
|
+
phrase: t("Set the pump of {device} to run {minutes} minutes per cycle", "Imposta la pompa di {device} a lavorare {minutes} minuti per ciclo"),
|
|
79312
|
+
icon: "timer",
|
|
79313
|
+
openArgs: [{
|
|
79314
|
+
key: "minutes",
|
|
79315
|
+
label: t("Minutes", "Minuti"),
|
|
79316
|
+
offer: {
|
|
79317
|
+
kind: "number",
|
|
79318
|
+
min: 0,
|
|
79319
|
+
step: 1,
|
|
79320
|
+
unit: "min"
|
|
79321
|
+
}
|
|
79322
|
+
}]
|
|
79323
|
+
},
|
|
79324
|
+
{
|
|
79325
|
+
id: "petFountain.pumpOffMinutes",
|
|
79326
|
+
method: "setPumpOffMinutes",
|
|
79327
|
+
label: t("Set pump rest time", "Imposta il tempo di riposo della pompa"),
|
|
79328
|
+
phrase: t("Set the pump of {device} to rest {minutes} minutes per cycle", "Imposta la pompa di {device} a riposare {minutes} minuti per ciclo"),
|
|
79329
|
+
icon: "timer-off",
|
|
79330
|
+
openArgs: [{
|
|
79331
|
+
key: "minutes",
|
|
79332
|
+
label: t("Minutes", "Minuti"),
|
|
79333
|
+
offer: {
|
|
79334
|
+
kind: "number",
|
|
79335
|
+
min: 0,
|
|
79336
|
+
step: 1,
|
|
79337
|
+
unit: "min"
|
|
79338
|
+
}
|
|
79339
|
+
}]
|
|
79340
|
+
},
|
|
79341
|
+
{
|
|
79342
|
+
id: "petFountain.resetDailyConsumption",
|
|
79343
|
+
method: "resetDailyConsumption",
|
|
79344
|
+
label: t("Clear daily consumption", "Azzera il consumo giornaliero"),
|
|
79345
|
+
phrase: t("Clear the daily water consumption of {device}", "Azzera il consumo giornaliero di acqua di {device}"),
|
|
79346
|
+
icon: "rotate-ccw"
|
|
79347
|
+
}
|
|
79348
|
+
],
|
|
79349
|
+
state: [{
|
|
79350
|
+
kind: "boolean",
|
|
79351
|
+
field: "empty",
|
|
79352
|
+
label: t("Tank empty", "Serbatoio vuoto"),
|
|
79353
|
+
whenTrue: t("When the tank of {device} is empty", "Quando il serbatoio di {device} è vuoto"),
|
|
79354
|
+
whenFalse: t("When the tank of {device} is refilled", "Quando il serbatoio di {device} viene riempito"),
|
|
79355
|
+
icon: "droplet"
|
|
79356
|
+
}, {
|
|
79357
|
+
kind: "numeric",
|
|
79358
|
+
field: "waterLevel",
|
|
79359
|
+
quantity: t("the water level", "il livello dell’acqua"),
|
|
79360
|
+
label: t("Water level", "Livello dell’acqua"),
|
|
79361
|
+
unit: "%",
|
|
79362
|
+
icon: "droplets"
|
|
79363
|
+
}]
|
|
79364
|
+
},
|
|
77759
79365
|
"media-player": {
|
|
77760
79366
|
scope: "device",
|
|
77761
79367
|
noun: t("Media player", "Lettore multimediale"),
|
|
@@ -77893,10 +79499,10 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
77893
79499
|
id: "media.seek",
|
|
77894
79500
|
method: "seek",
|
|
77895
79501
|
label: t("Seek", "Vai al punto"),
|
|
77896
|
-
phrase: t("Move {device} to {
|
|
79502
|
+
phrase: t("Move {device} to {position}", "Porta {device} al punto {position}"),
|
|
77897
79503
|
icon: "fast-forward",
|
|
77898
79504
|
openArgs: [{
|
|
77899
|
-
key: "
|
|
79505
|
+
key: "position",
|
|
77900
79506
|
label: t("Position", "Posizione"),
|
|
77901
79507
|
offer: {
|
|
77902
79508
|
kind: "number",
|
|
@@ -78945,7 +80551,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78945
80551
|
state: [
|
|
78946
80552
|
{
|
|
78947
80553
|
kind: "numeric",
|
|
78948
|
-
field: "
|
|
80554
|
+
field: "co2",
|
|
78949
80555
|
quantity: t("the CO₂", "la CO₂"),
|
|
78950
80556
|
label: t("CO₂", "CO₂"),
|
|
78951
80557
|
unit: "ppm",
|
|
@@ -78953,7 +80559,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78953
80559
|
},
|
|
78954
80560
|
{
|
|
78955
80561
|
kind: "numeric",
|
|
78956
|
-
field: "
|
|
80562
|
+
field: "voc",
|
|
78957
80563
|
quantity: t("the VOC level", "il livello di COV"),
|
|
78958
80564
|
label: t("VOC", "COV"),
|
|
78959
80565
|
unit: "ppb",
|
|
@@ -78989,7 +80595,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78989
80595
|
noun: t("Light level", "Luminosità ambiente"),
|
|
78990
80596
|
state: [{
|
|
78991
80597
|
kind: "numeric",
|
|
78992
|
-
field: "
|
|
80598
|
+
field: "illuminance",
|
|
78993
80599
|
quantity: t("the light level", "la luminosità"),
|
|
78994
80600
|
label: t("Illuminance", "Illuminamento"),
|
|
78995
80601
|
unit: "lx",
|
|
@@ -79192,7 +80798,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79192
80798
|
noun: t("Humidity", "Umidità"),
|
|
79193
80799
|
state: [{
|
|
79194
80800
|
kind: "numeric",
|
|
79195
|
-
field: "
|
|
80801
|
+
field: "humidity",
|
|
79196
80802
|
quantity: t("the humidity", "l’umidità"),
|
|
79197
80803
|
label: t("Humidity", "Umidità"),
|
|
79198
80804
|
unit: "%",
|
|
@@ -79240,7 +80846,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79240
80846
|
state: [
|
|
79241
80847
|
{
|
|
79242
80848
|
kind: "numeric",
|
|
79243
|
-
field: "
|
|
80849
|
+
field: "power",
|
|
79244
80850
|
quantity: t("the power draw", "il consumo"),
|
|
79245
80851
|
label: t("Power", "Potenza"),
|
|
79246
80852
|
unit: "W",
|
|
@@ -79248,7 +80854,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79248
80854
|
},
|
|
79249
80855
|
{
|
|
79250
80856
|
kind: "numeric",
|
|
79251
|
-
field: "
|
|
80857
|
+
field: "energy",
|
|
79252
80858
|
quantity: t("the energy used", "l’energia consumata"),
|
|
79253
80859
|
label: t("Energy", "Energia"),
|
|
79254
80860
|
unit: "kWh",
|
|
@@ -79256,7 +80862,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79256
80862
|
},
|
|
79257
80863
|
{
|
|
79258
80864
|
kind: "numeric",
|
|
79259
|
-
field: "
|
|
80865
|
+
field: "voltage",
|
|
79260
80866
|
quantity: t("the voltage", "la tensione"),
|
|
79261
80867
|
label: t("Voltage", "Tensione"),
|
|
79262
80868
|
unit: "V",
|
|
@@ -79264,7 +80870,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79264
80870
|
},
|
|
79265
80871
|
{
|
|
79266
80872
|
kind: "numeric",
|
|
79267
|
-
field: "
|
|
80873
|
+
field: "current",
|
|
79268
80874
|
quantity: t("the current", "la corrente"),
|
|
79269
80875
|
label: t("Current", "Corrente"),
|
|
79270
80876
|
unit: "A",
|
|
@@ -79281,13 +80887,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79281
80887
|
label: t("Where", "Posizione"),
|
|
79282
80888
|
phrase: t("When {device} is at {value}", "Quando {device} è in {value}"),
|
|
79283
80889
|
icon: "map-pin"
|
|
79284
|
-
}, {
|
|
79285
|
-
kind: "numeric",
|
|
79286
|
-
field: "batteryPercent",
|
|
79287
|
-
quantity: t("the phone battery", "la batteria del telefono"),
|
|
79288
|
-
label: t("Battery", "Batteria"),
|
|
79289
|
-
unit: "%",
|
|
79290
|
-
icon: "battery"
|
|
79291
80890
|
}]
|
|
79292
80891
|
},
|
|
79293
80892
|
"pressure-sensor": {
|
|
@@ -79295,7 +80894,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79295
80894
|
noun: t("Pressure", "Pressione"),
|
|
79296
80895
|
state: [{
|
|
79297
80896
|
kind: "numeric",
|
|
79298
|
-
field: "
|
|
80897
|
+
field: "pressure",
|
|
79299
80898
|
quantity: t("the pressure", "la pressione"),
|
|
79300
80899
|
label: t("Pressure", "Pressione"),
|
|
79301
80900
|
unit: "hPa",
|
|
@@ -79331,7 +80930,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79331
80930
|
noun: t("Temperature", "Temperatura"),
|
|
79332
80931
|
state: [{
|
|
79333
80932
|
kind: "numeric",
|
|
79334
|
-
field: "
|
|
80933
|
+
field: "temperature",
|
|
79335
80934
|
quantity: t("the temperature", "la temperatura"),
|
|
79336
80935
|
label: t("Temperature", "Temperatura"),
|
|
79337
80936
|
unit: "°C",
|
|
@@ -79402,7 +81001,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79402
81001
|
state: [
|
|
79403
81002
|
{
|
|
79404
81003
|
kind: "numeric",
|
|
79405
|
-
field: "
|
|
81004
|
+
field: "level",
|
|
79406
81005
|
quantity: t("the battery level", "il livello della batteria"),
|
|
79407
81006
|
label: t("Battery", "Batteria"),
|
|
79408
81007
|
unit: "%",
|
|
@@ -79444,7 +81043,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79444
81043
|
icon: "battery-charging"
|
|
79445
81044
|
}
|
|
79446
81045
|
],
|
|
79447
|
-
events: { onStatusChanged: { notOperatorFacing: "the
|
|
81046
|
+
events: { onStatusChanged: { notOperatorFacing: "the level / sleeping / charging state triggers each read one field of this change" } },
|
|
79448
81047
|
extraEvents: [{
|
|
79449
81048
|
category: EventCategory.DeviceAwake,
|
|
79450
81049
|
label: t("Woke up", "Risvegliato"),
|
|
@@ -79462,7 +81061,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79462
81061
|
noun: t("Network link", "Collegamento di rete"),
|
|
79463
81062
|
state: [{
|
|
79464
81063
|
kind: "numeric",
|
|
79465
|
-
field: "
|
|
81064
|
+
field: "signal",
|
|
79466
81065
|
quantity: t("the signal strength", "l’intensità del segnale"),
|
|
79467
81066
|
label: t("Signal", "Segnale"),
|
|
79468
81067
|
unit: "%",
|
|
@@ -79555,6 +81154,8 @@ var ML = "model and training machinery — no device action";
|
|
|
79555
81154
|
var INTERNAL = "internal plumbing between addons — never operator-facing";
|
|
79556
81155
|
/** Every system-scoped cap, with why it is not a device's vocabulary. */
|
|
79557
81156
|
var SYSTEM_CAP_VOCABULARY = {
|
|
81157
|
+
"action-source": system(INTERNAL),
|
|
81158
|
+
actions: system("declared actions — run from the Actions page and from the cameras that link them"),
|
|
79558
81159
|
"addon-pages": system(UI_PLUMBING),
|
|
79559
81160
|
"addon-pages-source": system(UI_PLUMBING),
|
|
79560
81161
|
"addon-routes": system(UI_PLUMBING),
|
|
@@ -79585,6 +81186,7 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
79585
81186
|
"device-manager": system("the device registry itself — rename, move and remove are administration"),
|
|
79586
81187
|
"device-provider": system(INTERNAL),
|
|
79587
81188
|
"device-removal-hook": system(INTERNAL),
|
|
81189
|
+
"node-removal-hook": system(INTERNAL),
|
|
79588
81190
|
"device-state": system("the runtime-state mirror every trigger already reads through"),
|
|
79589
81191
|
"display-palette": system("the cluster display palette — one colour table for every client, not a device action"),
|
|
79590
81192
|
"embedding-encoder": system(ML),
|
|
@@ -79624,6 +81226,7 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
79624
81226
|
"recording-archive": system(STORAGE),
|
|
79625
81227
|
"recording-export": system("recording exports — requested from the timeline, not an automation step"),
|
|
79626
81228
|
records: system(INTERNAL),
|
|
81229
|
+
remote: system("the per-device remote setup — authored in the Customize remote editor, sent through the remote UI"),
|
|
79627
81230
|
"server-management": system(CLUSTER),
|
|
79628
81231
|
"settings-store": system(INTERNAL),
|
|
79629
81232
|
"smtp-provider": system(INTERNAL),
|
|
@@ -79636,6 +81239,7 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
79636
81239
|
"storage-provider": system(STORAGE),
|
|
79637
81240
|
"stream-broker": system(PIPELINE),
|
|
79638
81241
|
system: system(CLUSTER),
|
|
81242
|
+
template: system("operator-authored templates — edited in their own editor, never actuated"),
|
|
79639
81243
|
"terminal-session": system(CLUSTER),
|
|
79640
81244
|
toast: system(UI_PLUMBING),
|
|
79641
81245
|
training: system(ML),
|
|
@@ -79695,7 +81299,7 @@ function projectAction(cap, action) {
|
|
|
79695
81299
|
};
|
|
79696
81300
|
}
|
|
79697
81301
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
79698
|
-
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;
|
|
81302
|
+
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.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer;
|
|
79699
81303
|
DeviceFeature.BatteryOperated;
|
|
79700
81304
|
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
79701
81305
|
var HA_AS = "a power sensor (device_class power). Home Assistant has no laundry domain. running-state stays unexported until a null reading can be published as unavailable.";
|
|
@@ -79751,6 +81355,31 @@ Object.freeze({
|
|
|
79751
81355
|
form: "single",
|
|
79752
81356
|
optional: false
|
|
79753
81357
|
}],
|
|
81358
|
+
"actions.get": [{
|
|
81359
|
+
name: "deviceId",
|
|
81360
|
+
form: "single",
|
|
81361
|
+
optional: true
|
|
81362
|
+
}],
|
|
81363
|
+
"actions.getLinks": [{
|
|
81364
|
+
name: "deviceId",
|
|
81365
|
+
form: "single",
|
|
81366
|
+
optional: false
|
|
81367
|
+
}],
|
|
81368
|
+
"actions.listForCamera": [{
|
|
81369
|
+
name: "deviceId",
|
|
81370
|
+
form: "single",
|
|
81371
|
+
optional: false
|
|
81372
|
+
}],
|
|
81373
|
+
"actions.run": [{
|
|
81374
|
+
name: "deviceId",
|
|
81375
|
+
form: "single",
|
|
81376
|
+
optional: true
|
|
81377
|
+
}],
|
|
81378
|
+
"actions.setLinks": [{
|
|
81379
|
+
name: "deviceId",
|
|
81380
|
+
form: "single",
|
|
81381
|
+
optional: false
|
|
81382
|
+
}],
|
|
79754
81383
|
"addonSettings.getDeviceSettings": [{
|
|
79755
81384
|
name: "deviceId",
|
|
79756
81385
|
form: "single",
|
|
@@ -80802,6 +82431,16 @@ Object.freeze({
|
|
|
80802
82431
|
form: "single",
|
|
80803
82432
|
optional: false
|
|
80804
82433
|
}],
|
|
82434
|
+
"irTransmitter.getInfo": [{
|
|
82435
|
+
name: "deviceId",
|
|
82436
|
+
form: "single",
|
|
82437
|
+
optional: false
|
|
82438
|
+
}],
|
|
82439
|
+
"irTransmitter.send": [{
|
|
82440
|
+
name: "deviceId",
|
|
82441
|
+
form: "single",
|
|
82442
|
+
optional: false
|
|
82443
|
+
}],
|
|
80805
82444
|
"keychain.deleteDeviceScope": [{
|
|
80806
82445
|
name: "deviceId",
|
|
80807
82446
|
form: "single",
|
|
@@ -81211,6 +82850,36 @@ Object.freeze({
|
|
|
81211
82850
|
form: "single",
|
|
81212
82851
|
optional: false
|
|
81213
82852
|
}],
|
|
82853
|
+
"petFountain.getStatus": [{
|
|
82854
|
+
name: "deviceId",
|
|
82855
|
+
form: "single",
|
|
82856
|
+
optional: false
|
|
82857
|
+
}],
|
|
82858
|
+
"petFountain.resetDailyConsumption": [{
|
|
82859
|
+
name: "deviceId",
|
|
82860
|
+
form: "single",
|
|
82861
|
+
optional: false
|
|
82862
|
+
}],
|
|
82863
|
+
"petFountain.setPump": [{
|
|
82864
|
+
name: "deviceId",
|
|
82865
|
+
form: "single",
|
|
82866
|
+
optional: false
|
|
82867
|
+
}],
|
|
82868
|
+
"petFountain.setPumpInterval": [{
|
|
82869
|
+
name: "deviceId",
|
|
82870
|
+
form: "single",
|
|
82871
|
+
optional: false
|
|
82872
|
+
}],
|
|
82873
|
+
"petFountain.setPumpOffMinutes": [{
|
|
82874
|
+
name: "deviceId",
|
|
82875
|
+
form: "single",
|
|
82876
|
+
optional: false
|
|
82877
|
+
}],
|
|
82878
|
+
"petFountain.setPumpOnMinutes": [{
|
|
82879
|
+
name: "deviceId",
|
|
82880
|
+
form: "single",
|
|
82881
|
+
optional: false
|
|
82882
|
+
}],
|
|
81214
82883
|
"pipelineAnalytics.addRetrainFrameFromRecording": [{
|
|
81215
82884
|
name: "deviceId",
|
|
81216
82885
|
form: "single",
|
|
@@ -82027,6 +83696,31 @@ Object.freeze({
|
|
|
82027
83696
|
form: "single",
|
|
82028
83697
|
optional: true
|
|
82029
83698
|
}],
|
|
83699
|
+
"remote.getConfig": [{
|
|
83700
|
+
name: "deviceId",
|
|
83701
|
+
form: "single",
|
|
83702
|
+
optional: false
|
|
83703
|
+
}],
|
|
83704
|
+
"remote.listCommands": [{
|
|
83705
|
+
name: "deviceId",
|
|
83706
|
+
form: "single",
|
|
83707
|
+
optional: false
|
|
83708
|
+
}],
|
|
83709
|
+
"remote.sendCommand": [{
|
|
83710
|
+
name: "deviceId",
|
|
83711
|
+
form: "single",
|
|
83712
|
+
optional: false
|
|
83713
|
+
}],
|
|
83714
|
+
"remote.sendMediaCommand": [{
|
|
83715
|
+
name: "deviceId",
|
|
83716
|
+
form: "single",
|
|
83717
|
+
optional: false
|
|
83718
|
+
}],
|
|
83719
|
+
"remote.setConfig": [{
|
|
83720
|
+
name: "deviceId",
|
|
83721
|
+
form: "single",
|
|
83722
|
+
optional: false
|
|
83723
|
+
}],
|
|
82030
83724
|
"runningState.getStatus": [{
|
|
82031
83725
|
name: "deviceId",
|
|
82032
83726
|
form: "single",
|
|
@@ -83832,8 +85526,17 @@ DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
|
|
|
83832
85526
|
DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
|
|
83833
85527
|
DEFAULT_NATIVE_LEASE_SETTINGS.sceneBudgetMb;
|
|
83834
85528
|
DEFAULT_NATIVE_LEASE_SETTINGS.admission;
|
|
85529
|
+
String.raw`(?<=^|["'(\s>,\[{])`;
|
|
83835
85530
|
var MB = 1024 * 1024;
|
|
83836
85531
|
1024 * MB, 3072 * MB;
|
|
85532
|
+
object({
|
|
85533
|
+
manufacturer: string().optional(),
|
|
85534
|
+
supportedModels: array(string()).optional(),
|
|
85535
|
+
supportedController: string().optional(),
|
|
85536
|
+
commandsEncoding: string(),
|
|
85537
|
+
delay: number().nonnegative().optional(),
|
|
85538
|
+
commands: record(string(), unknown())
|
|
85539
|
+
});
|
|
83837
85540
|
//#endregion
|
|
83838
85541
|
//#region src/custom-actions.ts
|
|
83839
85542
|
var SourceIdSchema = string().min(1).regex(/^[a-z0-9][a-z0-9-]{0,63}$/, "id must be a lowercase slug");
|