@camstack/addon-provider-reolink 1.2.207 → 1.2.209

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.
Files changed (3) hide show
  1. package/dist/addon.js +3260 -441
  2. package/dist/addon.mjs +3260 -441
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -36,7 +36,7 @@ let node_os = require("node:os");
36
36
  node_os = require_chunk.__toESM(node_os, 1);
37
37
  let node_fs = require("node:fs");
38
38
  node_fs = require_chunk.__toESM(node_fs, 1);
39
- //#region ../types/dist/event-category-BfJwUd2S.mjs
39
+ //#region ../types/dist/event-category-DHXxB8t9.mjs
40
40
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
41
41
  EventCategory["SystemBoot"] = "system.boot";
42
42
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -332,7 +332,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
332
332
  * TRANSITION into that state (never per dispatch), and the node is dropped
333
333
  * from the placement candidate set for as long as it holds.
334
334
  *
335
- * This exists because the state was previously invisible: little-unraid
335
+ * This exists because the state was previously invisible: agent-a
336
336
  * absorbed 283k inference errors in a day while still being handed cameras,
337
337
  * and nothing in the system said so.
338
338
  *
@@ -363,9 +363,8 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
363
363
  EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
364
364
  /**
365
365
  * Per-camera pipeline config was mutated by the orchestrator
366
- * (3-level settings change via `setAgentAddonDefaults` /
367
- * `setCameraStepToggle` / `setCameraPipelineForAgent` or a
368
- * pipeline-scoped `applyDeviceSettingsPatch`). Orchestrator
366
+ * (a settings change via `setAgentInferenceDevices` /
367
+ * `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
369
368
  * subscribes to its own emission to hot-reload the assigned runner
370
369
  * via `attachCamera` so the next frame executes against the new
371
370
  * engine/steps without waiting for a rebalance or the next
@@ -509,6 +508,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
509
508
  * on the device detail page.
510
509
  */
511
510
  EventCategory["DoorbellOnPressed"] = "doorbell.onPressed";
511
+ /** Mirrors `runningStateCapability.events.onStarted`. */
512
+ EventCategory["RunningStarted"] = "running.started";
513
+ /** Mirrors `runningStateCapability.events.onFinished`. */
514
+ EventCategory["RunningFinished"] = "running.finished";
512
515
  /**
513
516
  * Cap event fired by every device that registers the `event-emitter`
514
517
  * capability. Mirrors `eventEmitterCapability.events.onEvent`. Carries
@@ -5468,7 +5471,7 @@ var ZodIssueCode = {
5468
5471
  var ZodFirstPartyTypeKind;
5469
5472
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5470
5473
  //#endregion
5471
- //#region ../types/dist/sleep-6AqUnQIT.mjs
5474
+ //#region ../types/dist/sleep-BErAxhul.mjs
5472
5475
  /**
5473
5476
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5474
5477
  * window to float samples (D455).
@@ -5811,7 +5814,7 @@ Object.fromEntries([
5811
5814
  * `hydrateSchema` to skip the `value` injection for structural-only fields.
5812
5815
  */
5813
5816
  function isValuelessField(field) {
5814
- return field.type === "separator" || field.type === "info" || field.type === "qr-code" || field.type === "button" || field.type === "object-array" || field.type === "widget" || field.type === "addon-action-button" || field.type === "device-action-button";
5817
+ return field.type === "separator" || field.type === "info" || field.type === "qr-code" || field.type === "button" || field.type === "object-array" || field.type === "widget" || field.type === "addon-action-button" || field.type === "device-action-button" || field.type === "account-sign-in" || field.type === "secret-presence";
5815
5818
  }
5816
5819
  function hydrateSchema(schema, values, options = {}) {
5817
5820
  return {
@@ -8529,6 +8532,1980 @@ method(object({ deviceId: number() }), array(StreamSourceEntrySchema)), method(o
8529
8532
  kind: "mutation",
8530
8533
  auth: "admin"
8531
8534
  }), method(object({ deviceId: number() }), unknown().nullable()), method(object({ deviceId: number() }), RawStateResultSchema.nullable(), { auth: "protected" });
8535
+ Object.freeze({ "doorbell": "lastPressedAt" });
8536
+ /** Every capability name, so addon code can check a name without the schema graph. */
8537
+ var CAP_NAMES = Object.freeze([
8538
+ "accessories",
8539
+ "addon-pages",
8540
+ "addon-pages-source",
8541
+ "addon-routes",
8542
+ "addon-settings",
8543
+ "addon-widgets",
8544
+ "addon-widgets-source",
8545
+ "addons",
8546
+ "admin-ui",
8547
+ "air-quality-sensor",
8548
+ "alarm-panel",
8549
+ "alerts",
8550
+ "ambient-light-sensor",
8551
+ "audio-analysis",
8552
+ "audio-analyzer",
8553
+ "audio-codec",
8554
+ "audio-metrics",
8555
+ "auth-provider",
8556
+ "automation-control",
8557
+ "backup",
8558
+ "battery",
8559
+ "binary",
8560
+ "brightness",
8561
+ "broker",
8562
+ "button",
8563
+ "calendar-source",
8564
+ "calendars",
8565
+ "camera-credentials",
8566
+ "camera-grid-layout",
8567
+ "camera-pipeline-config",
8568
+ "camera-streams",
8569
+ "carbon-monoxide",
8570
+ "climate-control",
8571
+ "color",
8572
+ "composer",
8573
+ "connection-test",
8574
+ "connectivity",
8575
+ "consumables",
8576
+ "contact",
8577
+ "control",
8578
+ "core-blocks",
8579
+ "cover",
8580
+ "custom-model-registry",
8581
+ "data-store-provider",
8582
+ "database-snapshot",
8583
+ "day-night",
8584
+ "decoder",
8585
+ "detection-pipeline",
8586
+ "device-admin-link",
8587
+ "device-adoption",
8588
+ "device-credentials",
8589
+ "device-discovery",
8590
+ "device-export",
8591
+ "device-extension",
8592
+ "device-history",
8593
+ "device-manager",
8594
+ "device-ops",
8595
+ "device-provider",
8596
+ "device-removal-hook",
8597
+ "device-state",
8598
+ "device-status",
8599
+ "dishwasher",
8600
+ "display-palette",
8601
+ "doorbell",
8602
+ "embedding-encoder",
8603
+ "enum-sensor",
8604
+ "event-emitter",
8605
+ "face-gallery",
8606
+ "failure-contribution",
8607
+ "fan-control",
8608
+ "feature-probe",
8609
+ "filesystem-browse",
8610
+ "flood",
8611
+ "gas",
8612
+ "heating-valve",
8613
+ "humidifier",
8614
+ "humidity-sensor",
8615
+ "image",
8616
+ "image-settings",
8617
+ "integrations",
8618
+ "intercom",
8619
+ "keychain",
8620
+ "keychain-admin",
8621
+ "lawn-mower-control",
8622
+ "llm",
8623
+ "llm-runtime",
8624
+ "load-contribution",
8625
+ "local-network",
8626
+ "lock-control",
8627
+ "log-channels",
8628
+ "log-destination",
8629
+ "login-method",
8630
+ "media-player",
8631
+ "mesh-network",
8632
+ "metrics-provider",
8633
+ "model-convert",
8634
+ "model-distributor",
8635
+ "motion",
8636
+ "motion-detection",
8637
+ "motion-trigger",
8638
+ "motion-zones",
8639
+ "mqtt-broker",
8640
+ "native-object-detection",
8641
+ "navigation",
8642
+ "network-access",
8643
+ "network-link",
8644
+ "network-quality",
8645
+ "node-certificates",
8646
+ "nodes",
8647
+ "notification-output",
8648
+ "notification-rules",
8649
+ "notifier",
8650
+ "numeric-sensor",
8651
+ "oauth-integration",
8652
+ "oidc-connections",
8653
+ "osd",
8654
+ "osd-manager",
8655
+ "pet-feeder",
8656
+ "pipeline-analytics",
8657
+ "pipeline-executor",
8658
+ "pipeline-orchestrator",
8659
+ "pipeline-runner",
8660
+ "plate-gallery",
8661
+ "platform-probe",
8662
+ "power-meter",
8663
+ "presence",
8664
+ "pressure-sensor",
8665
+ "privacy-mask",
8666
+ "ptz",
8667
+ "ptz-autotrack",
8668
+ "reboot",
8669
+ "record-entries",
8670
+ "recording",
8671
+ "recording-archive",
8672
+ "recording-export",
8673
+ "recording-onboard",
8674
+ "recording-signal",
8675
+ "records",
8676
+ "running-state",
8677
+ "scene-monitor",
8678
+ "script-runner",
8679
+ "server-management",
8680
+ "settings-store",
8681
+ "smoke",
8682
+ "smtp-provider",
8683
+ "snapshot",
8684
+ "sso-bridge",
8685
+ "storage",
8686
+ "storage-admin",
8687
+ "storage-evictable",
8688
+ "storage-migration",
8689
+ "storage-occupancy",
8690
+ "storage-provider",
8691
+ "stream-broker",
8692
+ "stream-catalog",
8693
+ "stream-params",
8694
+ "stream-signals",
8695
+ "switch",
8696
+ "system",
8697
+ "tamper",
8698
+ "temperature-sensor",
8699
+ "terminal-session",
8700
+ "toast",
8701
+ "training",
8702
+ "training-provider",
8703
+ "turn-provider",
8704
+ "update",
8705
+ "user-management",
8706
+ "user-passkeys",
8707
+ "vacuum-control",
8708
+ "valve",
8709
+ "vector-store",
8710
+ "vibration",
8711
+ "videoclips",
8712
+ "viewer-ui",
8713
+ "water-heater",
8714
+ "weather",
8715
+ "webrtc-session",
8716
+ "zone-analytics",
8717
+ "zone-rules",
8718
+ "zones"
8719
+ ]);
8720
+ Object.freeze({
8721
+ "air-quality-sensor": [
8722
+ {
8723
+ "path": "co2Ppm",
8724
+ "valueType": "number"
8725
+ },
8726
+ {
8727
+ "path": "vocPpb",
8728
+ "valueType": "number"
8729
+ },
8730
+ {
8731
+ "path": "pm25",
8732
+ "valueType": "number"
8733
+ },
8734
+ {
8735
+ "path": "pm10",
8736
+ "valueType": "number"
8737
+ },
8738
+ {
8739
+ "path": "aqi",
8740
+ "valueType": "number"
8741
+ },
8742
+ {
8743
+ "path": "unit",
8744
+ "valueType": "string"
8745
+ },
8746
+ {
8747
+ "path": "precision",
8748
+ "valueType": "number"
8749
+ }
8750
+ ],
8751
+ "alarm-panel": [
8752
+ {
8753
+ "path": "state",
8754
+ "valueType": "enum",
8755
+ "enumValues": [
8756
+ "disarmed",
8757
+ "armed_home",
8758
+ "armed_away",
8759
+ "armed_night",
8760
+ "armed_vacation",
8761
+ "armed_custom_bypass",
8762
+ "arming",
8763
+ "disarming",
8764
+ "pending",
8765
+ "triggered"
8766
+ ]
8767
+ },
8768
+ {
8769
+ "path": "targetMode",
8770
+ "valueType": "enum",
8771
+ "enumValues": [
8772
+ "home",
8773
+ "away",
8774
+ "night",
8775
+ "vacation",
8776
+ "custom_bypass"
8777
+ ]
8778
+ },
8779
+ {
8780
+ "path": "requiresCode",
8781
+ "valueType": "boolean"
8782
+ }
8783
+ ],
8784
+ "ambient-light-sensor": [
8785
+ {
8786
+ "path": "lux",
8787
+ "valueType": "number"
8788
+ },
8789
+ {
8790
+ "path": "unit",
8791
+ "valueType": "string"
8792
+ },
8793
+ {
8794
+ "path": "precision",
8795
+ "valueType": "number"
8796
+ }
8797
+ ],
8798
+ "audio-metrics": [
8799
+ {
8800
+ "path": "ts",
8801
+ "valueType": "number"
8802
+ },
8803
+ {
8804
+ "path": "windowSec",
8805
+ "valueType": "number"
8806
+ },
8807
+ {
8808
+ "path": "level.rms",
8809
+ "valueType": "number"
8810
+ },
8811
+ {
8812
+ "path": "level.dbfs",
8813
+ "valueType": "number"
8814
+ },
8815
+ {
8816
+ "path": "peakDbfs",
8817
+ "valueType": "number"
8818
+ },
8819
+ {
8820
+ "path": "avgDbfs",
8821
+ "valueType": "number"
8822
+ },
8823
+ {
8824
+ "path": "current.className",
8825
+ "valueType": "string"
8826
+ },
8827
+ {
8828
+ "path": "current.score",
8829
+ "valueType": "number"
8830
+ },
8831
+ {
8832
+ "path": "current.timestamp",
8833
+ "valueType": "number"
8834
+ }
8835
+ ],
8836
+ "automation-control": [
8837
+ {
8838
+ "path": "enabled",
8839
+ "valueType": "boolean"
8840
+ },
8841
+ {
8842
+ "path": "isRunning",
8843
+ "valueType": "boolean"
8844
+ },
8845
+ {
8846
+ "path": "lastTriggeredAt",
8847
+ "valueType": "number"
8848
+ },
8849
+ {
8850
+ "path": "lastError",
8851
+ "valueType": "string"
8852
+ }
8853
+ ],
8854
+ "battery": [
8855
+ {
8856
+ "path": "percentage",
8857
+ "valueType": "number"
8858
+ },
8859
+ {
8860
+ "path": "charging",
8861
+ "valueType": "enum",
8862
+ "enumValues": [
8863
+ "dc",
8864
+ "solar",
8865
+ "none",
8866
+ "unknown"
8867
+ ]
8868
+ },
8869
+ {
8870
+ "path": "sleeping",
8871
+ "valueType": "boolean"
8872
+ },
8873
+ {
8874
+ "path": "lastUpdated",
8875
+ "valueType": "number"
8876
+ },
8877
+ {
8878
+ "path": "lastContactAt",
8879
+ "valueType": "number"
8880
+ },
8881
+ {
8882
+ "path": "lastFullRefreshAt",
8883
+ "valueType": "number"
8884
+ },
8885
+ {
8886
+ "path": "binary",
8887
+ "valueType": "boolean"
8888
+ }
8889
+ ],
8890
+ "binary": [{
8891
+ "path": "on",
8892
+ "valueType": "boolean"
8893
+ }],
8894
+ "brightness": [{
8895
+ "path": "percentage",
8896
+ "valueType": "number"
8897
+ }],
8898
+ "broker": [{
8899
+ "path": "brokerCount",
8900
+ "valueType": "number"
8901
+ }, {
8902
+ "path": "connectedCount",
8903
+ "valueType": "number"
8904
+ }],
8905
+ "camera-credentials": [
8906
+ {
8907
+ "path": "host",
8908
+ "valueType": "string"
8909
+ },
8910
+ {
8911
+ "path": "port",
8912
+ "valueType": "number"
8913
+ },
8914
+ {
8915
+ "path": "onvifPort",
8916
+ "valueType": "number"
8917
+ },
8918
+ {
8919
+ "path": "rtspPort",
8920
+ "valueType": "number"
8921
+ },
8922
+ {
8923
+ "path": "https",
8924
+ "valueType": "boolean"
8925
+ },
8926
+ {
8927
+ "path": "hasUsername",
8928
+ "valueType": "boolean"
8929
+ },
8930
+ {
8931
+ "path": "hasPassword",
8932
+ "valueType": "boolean"
8933
+ },
8934
+ {
8935
+ "path": "onvifProfile",
8936
+ "valueType": "string"
8937
+ }
8938
+ ],
8939
+ "camera-streams": [
8940
+ {
8941
+ "path": "online",
8942
+ "valueType": "boolean"
8943
+ },
8944
+ {
8945
+ "path": "slotStatuses.high",
8946
+ "valueType": "enum",
8947
+ "enumValues": [
8948
+ "unassigned",
8949
+ "idle",
8950
+ "connecting",
8951
+ "streaming",
8952
+ "error"
8953
+ ]
8954
+ },
8955
+ {
8956
+ "path": "slotStatuses.mid",
8957
+ "valueType": "enum",
8958
+ "enumValues": [
8959
+ "unassigned",
8960
+ "idle",
8961
+ "connecting",
8962
+ "streaming",
8963
+ "error"
8964
+ ]
8965
+ },
8966
+ {
8967
+ "path": "slotStatuses.low",
8968
+ "valueType": "enum",
8969
+ "enumValues": [
8970
+ "unassigned",
8971
+ "idle",
8972
+ "connecting",
8973
+ "streaming",
8974
+ "error"
8975
+ ]
8976
+ },
8977
+ {
8978
+ "path": "slotErrors.high",
8979
+ "valueType": "string"
8980
+ },
8981
+ {
8982
+ "path": "slotErrors.mid",
8983
+ "valueType": "string"
8984
+ },
8985
+ {
8986
+ "path": "slotErrors.low",
8987
+ "valueType": "string"
8988
+ }
8989
+ ],
8990
+ "carbon-monoxide": [{
8991
+ "path": "detected",
8992
+ "valueType": "boolean"
8993
+ }],
8994
+ "climate-control": [
8995
+ {
8996
+ "path": "mode",
8997
+ "valueType": "enum",
8998
+ "enumValues": [
8999
+ "off",
9000
+ "heat",
9001
+ "cool",
9002
+ "auto",
9003
+ "heat_cool",
9004
+ "fan_only",
9005
+ "dry"
9006
+ ]
9007
+ },
9008
+ {
9009
+ "path": "fanMode",
9010
+ "valueType": "string"
9011
+ },
9012
+ {
9013
+ "path": "preset",
9014
+ "valueType": "string"
9015
+ },
9016
+ {
9017
+ "path": "target",
9018
+ "valueType": "number"
9019
+ },
9020
+ {
9021
+ "path": "targetHigh",
9022
+ "valueType": "number"
9023
+ },
9024
+ {
9025
+ "path": "targetLow",
9026
+ "valueType": "number"
9027
+ },
9028
+ {
9029
+ "path": "targetHumidity",
9030
+ "valueType": "number"
9031
+ },
9032
+ {
9033
+ "path": "currentTemp",
9034
+ "valueType": "number"
9035
+ },
9036
+ {
9037
+ "path": "currentHumidity",
9038
+ "valueType": "number"
9039
+ },
9040
+ {
9041
+ "path": "swingVertical",
9042
+ "valueType": "boolean"
9043
+ },
9044
+ {
9045
+ "path": "swingHorizontal",
9046
+ "valueType": "boolean"
9047
+ },
9048
+ {
9049
+ "path": "minTemp",
9050
+ "valueType": "number"
9051
+ },
9052
+ {
9053
+ "path": "maxTemp",
9054
+ "valueType": "number"
9055
+ },
9056
+ {
9057
+ "path": "tempStep",
9058
+ "valueType": "number"
9059
+ }
9060
+ ],
9061
+ "color": [
9062
+ {
9063
+ "path": "mode",
9064
+ "valueType": "enum",
9065
+ "enumValues": [
9066
+ "rgb",
9067
+ "hsv",
9068
+ "mired"
9069
+ ]
9070
+ },
9071
+ {
9072
+ "path": "rgb.r",
9073
+ "valueType": "number"
9074
+ },
9075
+ {
9076
+ "path": "rgb.g",
9077
+ "valueType": "number"
9078
+ },
9079
+ {
9080
+ "path": "rgb.b",
9081
+ "valueType": "number"
9082
+ },
9083
+ {
9084
+ "path": "hsv.h",
9085
+ "valueType": "number"
9086
+ },
9087
+ {
9088
+ "path": "hsv.s",
9089
+ "valueType": "number"
9090
+ },
9091
+ {
9092
+ "path": "hsv.v",
9093
+ "valueType": "number"
9094
+ },
9095
+ {
9096
+ "path": "mireds",
9097
+ "valueType": "number"
9098
+ }
9099
+ ],
9100
+ "connectivity": [{
9101
+ "path": "connected",
9102
+ "valueType": "boolean"
9103
+ }],
9104
+ "contact": [{
9105
+ "path": "entryOpen",
9106
+ "valueType": "boolean"
9107
+ }],
9108
+ "control": [
9109
+ {
9110
+ "path": "kind",
9111
+ "valueType": "enum",
9112
+ "enumValues": [
9113
+ "numeric",
9114
+ "select",
9115
+ "text",
9116
+ "datetime"
9117
+ ]
9118
+ },
9119
+ {
9120
+ "path": "unit",
9121
+ "valueType": "string"
9122
+ },
9123
+ {
9124
+ "path": "min",
9125
+ "valueType": "number"
9126
+ },
9127
+ {
9128
+ "path": "max",
9129
+ "valueType": "number"
9130
+ },
9131
+ {
9132
+ "path": "step",
9133
+ "valueType": "number"
9134
+ },
9135
+ {
9136
+ "path": "precision",
9137
+ "valueType": "number"
9138
+ },
9139
+ {
9140
+ "path": "format",
9141
+ "valueType": "enum",
9142
+ "enumValues": [
9143
+ "date",
9144
+ "time",
9145
+ "datetime"
9146
+ ]
9147
+ }
9148
+ ],
9149
+ "cover": [
9150
+ {
9151
+ "path": "state",
9152
+ "valueType": "enum",
9153
+ "enumValues": [
9154
+ "open",
9155
+ "opening",
9156
+ "closing",
9157
+ "closed",
9158
+ "stopped"
9159
+ ]
9160
+ },
9161
+ {
9162
+ "path": "position",
9163
+ "valueType": "number"
9164
+ },
9165
+ {
9166
+ "path": "tiltPosition",
9167
+ "valueType": "number"
9168
+ }
9169
+ ],
9170
+ "day-night": [
9171
+ {
9172
+ "path": "mode",
9173
+ "valueType": "enum",
9174
+ "enumValues": [
9175
+ "auto",
9176
+ "day",
9177
+ "night",
9178
+ "schedule"
9179
+ ]
9180
+ },
9181
+ {
9182
+ "path": "sensitivity",
9183
+ "valueType": "number"
9184
+ },
9185
+ {
9186
+ "path": "switchDelaySec",
9187
+ "valueType": "number"
9188
+ }
9189
+ ],
9190
+ "device-adoption": [
9191
+ {
9192
+ "path": "lastDiscoveryAt",
9193
+ "valueType": "number"
9194
+ },
9195
+ {
9196
+ "path": "candidateCount",
9197
+ "valueType": "number"
9198
+ },
9199
+ {
9200
+ "path": "adoptedCount",
9201
+ "valueType": "number"
9202
+ },
9203
+ {
9204
+ "path": "lastError",
9205
+ "valueType": "string"
9206
+ }
9207
+ ],
9208
+ "device-discovery": [{
9209
+ "path": "lastDiscoveryAt",
9210
+ "valueType": "number"
9211
+ }, {
9212
+ "path": "lastError",
9213
+ "valueType": "string"
9214
+ }],
9215
+ "device-export": [
9216
+ {
9217
+ "path": "linkState",
9218
+ "valueType": "enum",
9219
+ "enumValues": [
9220
+ "unlinked",
9221
+ "linked",
9222
+ "error"
9223
+ ]
9224
+ },
9225
+ {
9226
+ "path": "exposedDeviceCount",
9227
+ "valueType": "number"
9228
+ },
9229
+ {
9230
+ "path": "error",
9231
+ "valueType": "string"
9232
+ },
9233
+ {
9234
+ "path": "setup.qr",
9235
+ "valueType": "string"
9236
+ },
9237
+ {
9238
+ "path": "setup.note",
9239
+ "valueType": "string"
9240
+ }
9241
+ ],
9242
+ "device-status": [{
9243
+ "path": "online",
9244
+ "valueType": "boolean"
9245
+ }],
9246
+ "dishwasher": [
9247
+ {
9248
+ "path": "availability",
9249
+ "valueType": "enum",
9250
+ "enumValues": [
9251
+ "available",
9252
+ "offline",
9253
+ "description-missing"
9254
+ ]
9255
+ },
9256
+ {
9257
+ "path": "state",
9258
+ "valueType": "enum",
9259
+ "enumValues": [
9260
+ "idle",
9261
+ "running",
9262
+ "paused",
9263
+ "finished",
9264
+ "error",
9265
+ "unavailable"
9266
+ ]
9267
+ },
9268
+ {
9269
+ "path": "operationState",
9270
+ "valueType": "enum",
9271
+ "enumValues": [
9272
+ "Inactive",
9273
+ "Ready",
9274
+ "DelayedStart",
9275
+ "Run",
9276
+ "Pause",
9277
+ "ActionRequired",
9278
+ "Finished",
9279
+ "Error",
9280
+ "Aborting"
9281
+ ]
9282
+ },
9283
+ {
9284
+ "path": "program",
9285
+ "valueType": "string"
9286
+ },
9287
+ {
9288
+ "path": "selectedProgram",
9289
+ "valueType": "string"
9290
+ },
9291
+ {
9292
+ "path": "remainingSeconds",
9293
+ "valueType": "number"
9294
+ },
9295
+ {
9296
+ "path": "delayedStartSeconds",
9297
+ "valueType": "number"
9298
+ },
9299
+ {
9300
+ "path": "progressPercent",
9301
+ "valueType": "number"
9302
+ },
9303
+ {
9304
+ "path": "doorOpen",
9305
+ "valueType": "boolean"
9306
+ },
9307
+ {
9308
+ "path": "doorLocked",
9309
+ "valueType": "boolean"
9310
+ },
9311
+ {
9312
+ "path": "remoteStartAllowed",
9313
+ "valueType": "boolean"
9314
+ },
9315
+ {
9316
+ "path": "remoteControlActive",
9317
+ "valueType": "boolean"
9318
+ },
9319
+ {
9320
+ "path": "localControlActive",
9321
+ "valueType": "boolean"
9322
+ },
9323
+ {
9324
+ "path": "powerOn",
9325
+ "valueType": "boolean"
9326
+ },
9327
+ {
9328
+ "path": "powerState",
9329
+ "valueType": "string"
9330
+ },
9331
+ {
9332
+ "path": "filterCleaningDue",
9333
+ "valueType": "boolean"
9334
+ },
9335
+ {
9336
+ "path": "machineCareDue",
9337
+ "valueType": "boolean"
9338
+ },
9339
+ {
9340
+ "path": "machineCareRemainingRuns",
9341
+ "valueType": "number"
9342
+ },
9343
+ {
9344
+ "path": "halfLoad",
9345
+ "valueType": "boolean"
9346
+ },
9347
+ {
9348
+ "path": "hygienePlus",
9349
+ "valueType": "boolean"
9350
+ },
9351
+ {
9352
+ "path": "extraDry",
9353
+ "valueType": "boolean"
9354
+ },
9355
+ {
9356
+ "path": "intensiveZone",
9357
+ "valueType": "boolean"
9358
+ },
9359
+ {
9360
+ "path": "varioSpeedPlus",
9361
+ "valueType": "boolean"
9362
+ },
9363
+ {
9364
+ "path": "childLock",
9365
+ "valueType": "boolean"
9366
+ },
9367
+ {
9368
+ "path": "errorCode",
9369
+ "valueType": "number"
9370
+ },
9371
+ {
9372
+ "path": "errorLabel",
9373
+ "valueType": "string"
9374
+ }
9375
+ ],
9376
+ "doorbell": [{
9377
+ "path": "lastPressedAt",
9378
+ "valueType": "number"
9379
+ }, {
9380
+ "path": "pressCountSinceStart",
9381
+ "valueType": "number"
9382
+ }],
9383
+ "enum-sensor": [{
9384
+ "path": "value",
9385
+ "valueType": "string"
9386
+ }, {
9387
+ "path": "format",
9388
+ "valueType": "enum",
9389
+ "enumValues": [
9390
+ "date",
9391
+ "time",
9392
+ "datetime"
9393
+ ]
9394
+ }],
9395
+ "event-emitter": [
9396
+ {
9397
+ "path": "lastEvent.deviceId",
9398
+ "valueType": "number"
9399
+ },
9400
+ {
9401
+ "path": "lastEvent.eventType",
9402
+ "valueType": "string"
9403
+ },
9404
+ {
9405
+ "path": "lastEvent.timestamp",
9406
+ "valueType": "number"
9407
+ },
9408
+ {
9409
+ "path": "lastEvent.seq",
9410
+ "valueType": "number"
9411
+ },
9412
+ {
9413
+ "path": "eventCountSinceStart",
9414
+ "valueType": "number"
9415
+ }
9416
+ ],
9417
+ "fan-control": [
9418
+ {
9419
+ "path": "percentage",
9420
+ "valueType": "number"
9421
+ },
9422
+ {
9423
+ "path": "percentageStep",
9424
+ "valueType": "number"
9425
+ },
9426
+ {
9427
+ "path": "preset",
9428
+ "valueType": "string"
9429
+ },
9430
+ {
9431
+ "path": "direction",
9432
+ "valueType": "enum",
9433
+ "enumValues": ["forward", "reverse"]
9434
+ },
9435
+ {
9436
+ "path": "oscillating",
9437
+ "valueType": "boolean"
9438
+ }
9439
+ ],
9440
+ "feature-probe": [
9441
+ {
9442
+ "path": "deviceType",
9443
+ "valueType": "string"
9444
+ },
9445
+ {
9446
+ "path": "model",
9447
+ "valueType": "string"
9448
+ },
9449
+ {
9450
+ "path": "channelCount",
9451
+ "valueType": "number"
9452
+ },
9453
+ {
9454
+ "path": "lastProbedAt",
9455
+ "valueType": "number"
9456
+ }
9457
+ ],
9458
+ "flood": [{
9459
+ "path": "flooded",
9460
+ "valueType": "boolean"
9461
+ }],
9462
+ "gas": [{
9463
+ "path": "detected",
9464
+ "valueType": "boolean"
9465
+ }],
9466
+ "heating-valve": [{
9467
+ "path": "position",
9468
+ "valueType": "number"
9469
+ }],
9470
+ "humidifier": [
9471
+ {
9472
+ "path": "on",
9473
+ "valueType": "boolean"
9474
+ },
9475
+ {
9476
+ "path": "currentHumidity",
9477
+ "valueType": "number"
9478
+ },
9479
+ {
9480
+ "path": "targetHumidity",
9481
+ "valueType": "number"
9482
+ },
9483
+ {
9484
+ "path": "mode",
9485
+ "valueType": "string"
9486
+ },
9487
+ {
9488
+ "path": "action",
9489
+ "valueType": "string"
9490
+ },
9491
+ {
9492
+ "path": "minHumidity",
9493
+ "valueType": "number"
9494
+ },
9495
+ {
9496
+ "path": "maxHumidity",
9497
+ "valueType": "number"
9498
+ }
9499
+ ],
9500
+ "humidity-sensor": [
9501
+ {
9502
+ "path": "percent",
9503
+ "valueType": "number"
9504
+ },
9505
+ {
9506
+ "path": "unit",
9507
+ "valueType": "string"
9508
+ },
9509
+ {
9510
+ "path": "precision",
9511
+ "valueType": "number"
9512
+ }
9513
+ ],
9514
+ "image": [{
9515
+ "path": "url",
9516
+ "valueType": "string"
9517
+ }, {
9518
+ "path": "lastUpdated",
9519
+ "valueType": "number"
9520
+ }],
9521
+ "image-settings": [
9522
+ {
9523
+ "path": "brightness",
9524
+ "valueType": "number"
9525
+ },
9526
+ {
9527
+ "path": "contrast",
9528
+ "valueType": "number"
9529
+ },
9530
+ {
9531
+ "path": "saturation",
9532
+ "valueType": "number"
9533
+ },
9534
+ {
9535
+ "path": "sharpness",
9536
+ "valueType": "number"
9537
+ },
9538
+ {
9539
+ "path": "mirror",
9540
+ "valueType": "boolean"
9541
+ },
9542
+ {
9543
+ "path": "flip",
9544
+ "valueType": "boolean"
9545
+ },
9546
+ {
9547
+ "path": "rotate",
9548
+ "valueType": "enum",
9549
+ "enumValues": [
9550
+ "0",
9551
+ "90",
9552
+ "180",
9553
+ "270"
9554
+ ]
9555
+ },
9556
+ {
9557
+ "path": "whiteBalance",
9558
+ "valueType": "enum",
9559
+ "enumValues": ["auto", "manual"]
9560
+ },
9561
+ {
9562
+ "path": "warmth",
9563
+ "valueType": "number"
9564
+ },
9565
+ {
9566
+ "path": "exposureMode",
9567
+ "valueType": "enum",
9568
+ "enumValues": ["auto", "manual"]
9569
+ },
9570
+ {
9571
+ "path": "backlightMode",
9572
+ "valueType": "enum",
9573
+ "enumValues": [
9574
+ "off",
9575
+ "blc",
9576
+ "wdr",
9577
+ "hlc"
9578
+ ]
9579
+ }
9580
+ ],
9581
+ "intercom": [
9582
+ {
9583
+ "path": "talking",
9584
+ "valueType": "boolean"
9585
+ },
9586
+ {
9587
+ "path": "lastSessionAt",
9588
+ "valueType": "number"
9589
+ },
9590
+ {
9591
+ "path": "ability.sampleRate",
9592
+ "valueType": "number"
9593
+ },
9594
+ {
9595
+ "path": "ability.duplex",
9596
+ "valueType": "enum",
9597
+ "enumValues": ["half", "full"]
9598
+ },
9599
+ {
9600
+ "path": "ability.maxBacklogMs",
9601
+ "valueType": "number"
9602
+ }
9603
+ ],
9604
+ "lawn-mower-control": [
9605
+ {
9606
+ "path": "activity",
9607
+ "valueType": "enum",
9608
+ "enumValues": [
9609
+ "idle",
9610
+ "mowing",
9611
+ "paused",
9612
+ "docked",
9613
+ "error"
9614
+ ]
9615
+ },
9616
+ {
9617
+ "path": "batteryLevel",
9618
+ "valueType": "number"
9619
+ },
9620
+ {
9621
+ "path": "progressPercent",
9622
+ "valueType": "number"
9623
+ },
9624
+ {
9625
+ "path": "currentCode",
9626
+ "valueType": "number"
9627
+ },
9628
+ {
9629
+ "path": "currentCodeLabel",
9630
+ "valueType": "string"
9631
+ },
9632
+ {
9633
+ "path": "severity",
9634
+ "valueType": "enum",
9635
+ "enumValues": [
9636
+ "info",
9637
+ "warning",
9638
+ "error"
9639
+ ]
9640
+ }
9641
+ ],
9642
+ "lock-control": [{
9643
+ "path": "state",
9644
+ "valueType": "enum",
9645
+ "enumValues": [
9646
+ "locked",
9647
+ "unlocked",
9648
+ "locking",
9649
+ "unlocking",
9650
+ "jammed"
9651
+ ]
9652
+ }],
9653
+ "media-player": [
9654
+ {
9655
+ "path": "state",
9656
+ "valueType": "enum",
9657
+ "enumValues": [
9658
+ "off",
9659
+ "on",
9660
+ "idle",
9661
+ "playing",
9662
+ "paused",
9663
+ "buffering",
9664
+ "standby"
9665
+ ]
9666
+ },
9667
+ {
9668
+ "path": "volumeLevel",
9669
+ "valueType": "number"
9670
+ },
9671
+ {
9672
+ "path": "isMuted",
9673
+ "valueType": "boolean"
9674
+ },
9675
+ {
9676
+ "path": "source",
9677
+ "valueType": "string"
9678
+ },
9679
+ {
9680
+ "path": "currentMedia.type",
9681
+ "valueType": "string"
9682
+ },
9683
+ {
9684
+ "path": "currentMedia.title",
9685
+ "valueType": "string"
9686
+ },
9687
+ {
9688
+ "path": "currentMedia.artist",
9689
+ "valueType": "string"
9690
+ },
9691
+ {
9692
+ "path": "currentMedia.album",
9693
+ "valueType": "string"
9694
+ },
9695
+ {
9696
+ "path": "currentMedia.imageUrl",
9697
+ "valueType": "string"
9698
+ },
9699
+ {
9700
+ "path": "positionMs",
9701
+ "valueType": "number"
9702
+ },
9703
+ {
9704
+ "path": "durationMs",
9705
+ "valueType": "number"
9706
+ },
9707
+ {
9708
+ "path": "shuffle",
9709
+ "valueType": "boolean"
9710
+ },
9711
+ {
9712
+ "path": "repeat",
9713
+ "valueType": "enum",
9714
+ "enumValues": [
9715
+ "off",
9716
+ "all",
9717
+ "one"
9718
+ ]
9719
+ }
9720
+ ],
9721
+ "motion": [
9722
+ {
9723
+ "path": "detected",
9724
+ "valueType": "boolean"
9725
+ },
9726
+ {
9727
+ "path": "lastDetectedAt",
9728
+ "valueType": "number"
9729
+ },
9730
+ {
9731
+ "path": "autoClearAfterMs",
9732
+ "valueType": "number"
9733
+ }
9734
+ ],
9735
+ "motion-trigger": [{
9736
+ "path": "enabled",
9737
+ "valueType": "boolean"
9738
+ }],
9739
+ "motion-zones": [{
9740
+ "path": "enabled",
9741
+ "valueType": "boolean"
9742
+ }, {
9743
+ "path": "sensitivity",
9744
+ "valueType": "number"
9745
+ }],
9746
+ "mqtt-broker": [{
9747
+ "path": "brokerCount",
9748
+ "valueType": "number"
9749
+ }, {
9750
+ "path": "embeddedRunning",
9751
+ "valueType": "boolean"
9752
+ }],
9753
+ "native-object-detection": [{
9754
+ "path": "enabled",
9755
+ "valueType": "boolean"
9756
+ }],
9757
+ "navigation": [
9758
+ {
9759
+ "path": "mode",
9760
+ "valueType": "enum",
9761
+ "enumValues": [
9762
+ "idle",
9763
+ "cleaning",
9764
+ "spot",
9765
+ "following",
9766
+ "goto",
9767
+ "returning",
9768
+ "paused",
9769
+ "unknown"
9770
+ ]
9771
+ },
9772
+ {
9773
+ "path": "following",
9774
+ "valueType": "boolean"
9775
+ },
9776
+ {
9777
+ "path": "flash",
9778
+ "valueType": "boolean"
9779
+ },
9780
+ {
9781
+ "path": "lightMode",
9782
+ "valueType": "enum",
9783
+ "enumValues": ["auto", "manual"]
9784
+ },
9785
+ {
9786
+ "path": "lightLevel",
9787
+ "valueType": "number"
9788
+ }
9789
+ ],
9790
+ "network-link": [
9791
+ {
9792
+ "path": "type",
9793
+ "valueType": "enum",
9794
+ "enumValues": [
9795
+ "wifi",
9796
+ "ethernet",
9797
+ "cellular",
9798
+ "unknown"
9799
+ ]
9800
+ },
9801
+ {
9802
+ "path": "signalPercent",
9803
+ "valueType": "number"
9804
+ },
9805
+ {
9806
+ "path": "rssiDbm",
9807
+ "valueType": "number"
9808
+ },
9809
+ {
9810
+ "path": "ssid",
9811
+ "valueType": "string"
9812
+ },
9813
+ {
9814
+ "path": "lastUpdated",
9815
+ "valueType": "number"
9816
+ }
9817
+ ],
9818
+ "notifier": [
9819
+ {
9820
+ "path": "lastSentAt",
9821
+ "valueType": "number"
9822
+ },
9823
+ {
9824
+ "path": "lastError",
9825
+ "valueType": "string"
9826
+ },
9827
+ {
9828
+ "path": "queueDepth",
9829
+ "valueType": "number"
9830
+ },
9831
+ {
9832
+ "path": "supports.image",
9833
+ "valueType": "boolean"
9834
+ },
9835
+ {
9836
+ "path": "supports.priority",
9837
+ "valueType": "boolean"
9838
+ },
9839
+ {
9840
+ "path": "supports.data",
9841
+ "valueType": "boolean"
9842
+ },
9843
+ {
9844
+ "path": "supports.actions",
9845
+ "valueType": "boolean"
9846
+ },
9847
+ {
9848
+ "path": "supports.recipients",
9849
+ "valueType": "boolean"
9850
+ }
9851
+ ],
9852
+ "numeric-sensor": [
9853
+ {
9854
+ "path": "value",
9855
+ "valueType": "number"
9856
+ },
9857
+ {
9858
+ "path": "unit",
9859
+ "valueType": "string"
9860
+ },
9861
+ {
9862
+ "path": "precision",
9863
+ "valueType": "number"
9864
+ }
9865
+ ],
9866
+ "pet-feeder": [
9867
+ {
9868
+ "path": "foodLevel",
9869
+ "valueType": "number"
9870
+ },
9871
+ {
9872
+ "path": "food1",
9873
+ "valueType": "number"
9874
+ },
9875
+ {
9876
+ "path": "food2",
9877
+ "valueType": "number"
9878
+ },
9879
+ {
9880
+ "path": "lowFood",
9881
+ "valueType": "boolean"
9882
+ },
9883
+ {
9884
+ "path": "batteryPower",
9885
+ "valueType": "number"
9886
+ },
9887
+ {
9888
+ "path": "desiccantLeftDays",
9889
+ "valueType": "number"
9890
+ },
9891
+ {
9892
+ "path": "feeding",
9893
+ "valueType": "boolean"
9894
+ },
9895
+ {
9896
+ "path": "status",
9897
+ "valueType": "enum",
9898
+ "enumValues": [
9899
+ "normal",
9900
+ "offline",
9901
+ "on_batteries"
9902
+ ]
9903
+ },
9904
+ {
9905
+ "path": "error",
9906
+ "valueType": "string"
9907
+ },
9908
+ {
9909
+ "path": "errorCode",
9910
+ "valueType": "number"
9911
+ },
9912
+ {
9913
+ "path": "isDualHopper",
9914
+ "valueType": "boolean"
9915
+ },
9916
+ {
9917
+ "path": "childLock",
9918
+ "valueType": "boolean"
9919
+ },
9920
+ {
9921
+ "path": "indicatorLight",
9922
+ "valueType": "boolean"
9923
+ },
9924
+ {
9925
+ "path": "feedSound",
9926
+ "valueType": "boolean"
9927
+ },
9928
+ {
9929
+ "path": "volume",
9930
+ "valueType": "number"
9931
+ }
9932
+ ],
9933
+ "power-meter": [
9934
+ {
9935
+ "path": "watts",
9936
+ "valueType": "number"
9937
+ },
9938
+ {
9939
+ "path": "kwhTotal",
9940
+ "valueType": "number"
9941
+ },
9942
+ {
9943
+ "path": "volts",
9944
+ "valueType": "number"
9945
+ },
9946
+ {
9947
+ "path": "amps",
9948
+ "valueType": "number"
9949
+ },
9950
+ {
9951
+ "path": "va",
9952
+ "valueType": "number"
9953
+ },
9954
+ {
9955
+ "path": "powerFactor",
9956
+ "valueType": "number"
9957
+ },
9958
+ {
9959
+ "path": "unit",
9960
+ "valueType": "string"
9961
+ },
9962
+ {
9963
+ "path": "precision",
9964
+ "valueType": "number"
9965
+ }
9966
+ ],
9967
+ "presence": [
9968
+ {
9969
+ "path": "state",
9970
+ "valueType": "string"
9971
+ },
9972
+ {
9973
+ "path": "location",
9974
+ "valueType": "string"
9975
+ },
9976
+ {
9977
+ "path": "gps.latitude",
9978
+ "valueType": "number"
9979
+ },
9980
+ {
9981
+ "path": "gps.longitude",
9982
+ "valueType": "number"
9983
+ },
9984
+ {
9985
+ "path": "gps.accuracyMeters",
9986
+ "valueType": "number"
9987
+ },
9988
+ {
9989
+ "path": "batteryPercent",
9990
+ "valueType": "number"
9991
+ }
9992
+ ],
9993
+ "pressure-sensor": [
9994
+ {
9995
+ "path": "hpa",
9996
+ "valueType": "number"
9997
+ },
9998
+ {
9999
+ "path": "unit",
10000
+ "valueType": "string"
10001
+ },
10002
+ {
10003
+ "path": "precision",
10004
+ "valueType": "number"
10005
+ }
10006
+ ],
10007
+ "privacy-mask": [{
10008
+ "path": "enabled",
10009
+ "valueType": "boolean"
10010
+ }, {
10011
+ "path": "audioEnabled",
10012
+ "valueType": "boolean"
10013
+ }],
10014
+ "ptz": [
10015
+ {
10016
+ "path": "pan",
10017
+ "valueType": "number"
10018
+ },
10019
+ {
10020
+ "path": "tilt",
10021
+ "valueType": "number"
10022
+ },
10023
+ {
10024
+ "path": "zoom",
10025
+ "valueType": "number"
10026
+ },
10027
+ {
10028
+ "path": "autofocus",
10029
+ "valueType": "boolean"
10030
+ }
10031
+ ],
10032
+ "ptz-autotrack": [
10033
+ {
10034
+ "path": "enabled",
10035
+ "valueType": "boolean"
10036
+ },
10037
+ {
10038
+ "path": "currentSettings.targetType",
10039
+ "valueType": "string"
10040
+ },
10041
+ {
10042
+ "path": "currentSettings.stopDelaySeconds",
10043
+ "valueType": "number"
10044
+ },
10045
+ {
10046
+ "path": "currentSettings.disappearDelaySeconds",
10047
+ "valueType": "number"
10048
+ }
10049
+ ],
10050
+ "recording-archive": [
10051
+ {
10052
+ "path": "deviceId",
10053
+ "valueType": "number"
10054
+ },
10055
+ {
10056
+ "path": "enabled",
10057
+ "valueType": "boolean"
10058
+ },
10059
+ {
10060
+ "path": "activeMode",
10061
+ "valueType": "enum",
10062
+ "enumValues": [
10063
+ "off",
10064
+ "events",
10065
+ "continuous",
10066
+ "on-device-decision"
10067
+ ]
10068
+ },
10069
+ {
10070
+ "path": "nodeId",
10071
+ "valueType": "string"
10072
+ },
10073
+ {
10074
+ "path": "storageBytes",
10075
+ "valueType": "number"
10076
+ }
10077
+ ],
10078
+ "recording-onboard": [
10079
+ {
10080
+ "path": "primaryTrackId",
10081
+ "valueType": "string"
10082
+ },
10083
+ {
10084
+ "path": "enabled",
10085
+ "valueType": "boolean"
10086
+ },
10087
+ {
10088
+ "path": "overwriteWhenFull",
10089
+ "valueType": "boolean"
10090
+ },
10091
+ {
10092
+ "path": "preRecordSec",
10093
+ "valueType": "number"
10094
+ },
10095
+ {
10096
+ "path": "postRecordSec",
10097
+ "valueType": "number"
10098
+ },
10099
+ {
10100
+ "path": "segmentMinutes",
10101
+ "valueType": "number"
10102
+ },
10103
+ {
10104
+ "path": "unreadableWindows",
10105
+ "valueType": "number"
10106
+ },
10107
+ {
10108
+ "path": "recordingToNowhere",
10109
+ "valueType": "boolean"
10110
+ }
10111
+ ],
10112
+ "recording-signal": [{
10113
+ "path": "active",
10114
+ "valueType": "boolean"
10115
+ }, {
10116
+ "path": "reason",
10117
+ "valueType": "string"
10118
+ }],
10119
+ "running-state": [
10120
+ {
10121
+ "path": "running",
10122
+ "valueType": "boolean"
10123
+ },
10124
+ {
10125
+ "path": "since",
10126
+ "valueType": "number"
10127
+ },
10128
+ {
10129
+ "path": "source",
10130
+ "valueType": "enum",
10131
+ "enumValues": ["native", "assigned"]
10132
+ },
10133
+ {
10134
+ "path": "phase",
10135
+ "valueType": "string"
10136
+ }
10137
+ ],
10138
+ "script-runner": [
10139
+ {
10140
+ "path": "isRunning",
10141
+ "valueType": "boolean"
10142
+ },
10143
+ {
10144
+ "path": "lastRunAt",
10145
+ "valueType": "number"
10146
+ },
10147
+ {
10148
+ "path": "lastRunSuccess",
10149
+ "valueType": "boolean"
10150
+ },
10151
+ {
10152
+ "path": "lastError",
10153
+ "valueType": "string"
10154
+ }
10155
+ ],
10156
+ "smoke": [{
10157
+ "path": "detected",
10158
+ "valueType": "boolean"
10159
+ }],
10160
+ "snapshot": [
10161
+ {
10162
+ "path": "lastCapturedAt",
10163
+ "valueType": "number"
10164
+ },
10165
+ {
10166
+ "path": "cacheAgeMs",
10167
+ "valueType": "number"
10168
+ },
10169
+ {
10170
+ "path": "lastBytes",
10171
+ "valueType": "number"
10172
+ },
10173
+ {
10174
+ "path": "lastStreamId",
10175
+ "valueType": "string"
10176
+ }
10177
+ ],
10178
+ "stream-params": [
10179
+ {
10180
+ "path": "main.width",
10181
+ "valueType": "number"
10182
+ },
10183
+ {
10184
+ "path": "main.height",
10185
+ "valueType": "number"
10186
+ },
10187
+ {
10188
+ "path": "main.codec",
10189
+ "valueType": "enum",
10190
+ "enumValues": ["h264", "h265"]
10191
+ },
10192
+ {
10193
+ "path": "main.framerate",
10194
+ "valueType": "number"
10195
+ },
10196
+ {
10197
+ "path": "main.bitrate",
10198
+ "valueType": "number"
10199
+ },
10200
+ {
10201
+ "path": "main.bitrateMode",
10202
+ "valueType": "enum",
10203
+ "enumValues": ["vbr", "cbr"]
10204
+ },
10205
+ {
10206
+ "path": "main.encoderProfile",
10207
+ "valueType": "enum",
10208
+ "enumValues": [
10209
+ "high",
10210
+ "main",
10211
+ "baseline"
10212
+ ]
10213
+ },
10214
+ {
10215
+ "path": "main.gop",
10216
+ "valueType": "number"
10217
+ },
10218
+ {
10219
+ "path": "main.audio",
10220
+ "valueType": "boolean"
10221
+ },
10222
+ {
10223
+ "path": "sub.width",
10224
+ "valueType": "number"
10225
+ },
10226
+ {
10227
+ "path": "sub.height",
10228
+ "valueType": "number"
10229
+ },
10230
+ {
10231
+ "path": "sub.codec",
10232
+ "valueType": "enum",
10233
+ "enumValues": ["h264", "h265"]
10234
+ },
10235
+ {
10236
+ "path": "sub.framerate",
10237
+ "valueType": "number"
10238
+ },
10239
+ {
10240
+ "path": "sub.bitrate",
10241
+ "valueType": "number"
10242
+ },
10243
+ {
10244
+ "path": "sub.bitrateMode",
10245
+ "valueType": "enum",
10246
+ "enumValues": ["vbr", "cbr"]
10247
+ },
10248
+ {
10249
+ "path": "sub.encoderProfile",
10250
+ "valueType": "enum",
10251
+ "enumValues": [
10252
+ "high",
10253
+ "main",
10254
+ "baseline"
10255
+ ]
10256
+ },
10257
+ {
10258
+ "path": "sub.gop",
10259
+ "valueType": "number"
10260
+ },
10261
+ {
10262
+ "path": "sub.audio",
10263
+ "valueType": "boolean"
10264
+ },
10265
+ {
10266
+ "path": "ext.width",
10267
+ "valueType": "number"
10268
+ },
10269
+ {
10270
+ "path": "ext.height",
10271
+ "valueType": "number"
10272
+ },
10273
+ {
10274
+ "path": "ext.codec",
10275
+ "valueType": "enum",
10276
+ "enumValues": ["h264", "h265"]
10277
+ },
10278
+ {
10279
+ "path": "ext.framerate",
10280
+ "valueType": "number"
10281
+ },
10282
+ {
10283
+ "path": "ext.bitrate",
10284
+ "valueType": "number"
10285
+ },
10286
+ {
10287
+ "path": "ext.bitrateMode",
10288
+ "valueType": "enum",
10289
+ "enumValues": ["vbr", "cbr"]
10290
+ },
10291
+ {
10292
+ "path": "ext.encoderProfile",
10293
+ "valueType": "enum",
10294
+ "enumValues": [
10295
+ "high",
10296
+ "main",
10297
+ "baseline"
10298
+ ]
10299
+ },
10300
+ {
10301
+ "path": "ext.gop",
10302
+ "valueType": "number"
10303
+ },
10304
+ {
10305
+ "path": "ext.audio",
10306
+ "valueType": "boolean"
10307
+ }
10308
+ ],
10309
+ "switch": [{
10310
+ "path": "on",
10311
+ "valueType": "boolean"
10312
+ }],
10313
+ "tamper": [{
10314
+ "path": "tampered",
10315
+ "valueType": "boolean"
10316
+ }],
10317
+ "temperature-sensor": [
10318
+ {
10319
+ "path": "celsius",
10320
+ "valueType": "number"
10321
+ },
10322
+ {
10323
+ "path": "unit",
10324
+ "valueType": "string"
10325
+ },
10326
+ {
10327
+ "path": "precision",
10328
+ "valueType": "number"
10329
+ }
10330
+ ],
10331
+ "update": [
10332
+ {
10333
+ "path": "currentVersion",
10334
+ "valueType": "string"
10335
+ },
10336
+ {
10337
+ "path": "availableVersion",
10338
+ "valueType": "string"
10339
+ },
10340
+ {
10341
+ "path": "updatable",
10342
+ "valueType": "boolean"
10343
+ },
10344
+ {
10345
+ "path": "state",
10346
+ "valueType": "string"
10347
+ },
10348
+ {
10349
+ "path": "inProgress",
10350
+ "valueType": "boolean"
10351
+ }
10352
+ ],
10353
+ "vacuum-control": [
10354
+ {
10355
+ "path": "state",
10356
+ "valueType": "enum",
10357
+ "enumValues": [
10358
+ "idle",
10359
+ "cleaning",
10360
+ "paused",
10361
+ "returning",
10362
+ "docked",
10363
+ "drying",
10364
+ "error"
10365
+ ]
10366
+ },
10367
+ {
10368
+ "path": "batteryLevel",
10369
+ "valueType": "number"
10370
+ },
10371
+ {
10372
+ "path": "fanSpeed",
10373
+ "valueType": "string"
10374
+ },
10375
+ {
10376
+ "path": "progressPercent",
10377
+ "valueType": "number"
10378
+ },
10379
+ {
10380
+ "path": "errorCode",
10381
+ "valueType": "number"
10382
+ },
10383
+ {
10384
+ "path": "errorLabel",
10385
+ "valueType": "string"
10386
+ }
10387
+ ],
10388
+ "valve": [{
10389
+ "path": "state",
10390
+ "valueType": "enum",
10391
+ "enumValues": [
10392
+ "open",
10393
+ "opening",
10394
+ "closing",
10395
+ "closed",
10396
+ "stopped"
10397
+ ]
10398
+ }, {
10399
+ "path": "position",
10400
+ "valueType": "number"
10401
+ }],
10402
+ "vibration": [{
10403
+ "path": "detected",
10404
+ "valueType": "boolean"
10405
+ }],
10406
+ "water-heater": [
10407
+ {
10408
+ "path": "currentTemp",
10409
+ "valueType": "number"
10410
+ },
10411
+ {
10412
+ "path": "targetTemp",
10413
+ "valueType": "number"
10414
+ },
10415
+ {
10416
+ "path": "operationMode",
10417
+ "valueType": "string"
10418
+ },
10419
+ {
10420
+ "path": "away",
10421
+ "valueType": "boolean"
10422
+ },
10423
+ {
10424
+ "path": "minTemp",
10425
+ "valueType": "number"
10426
+ },
10427
+ {
10428
+ "path": "maxTemp",
10429
+ "valueType": "number"
10430
+ }
10431
+ ],
10432
+ "weather": [
10433
+ {
10434
+ "path": "condition",
10435
+ "valueType": "string"
10436
+ },
10437
+ {
10438
+ "path": "temperature",
10439
+ "valueType": "number"
10440
+ },
10441
+ {
10442
+ "path": "temperatureUnit",
10443
+ "valueType": "string"
10444
+ },
10445
+ {
10446
+ "path": "humidity",
10447
+ "valueType": "number"
10448
+ },
10449
+ {
10450
+ "path": "pressure",
10451
+ "valueType": "number"
10452
+ },
10453
+ {
10454
+ "path": "pressureUnit",
10455
+ "valueType": "string"
10456
+ },
10457
+ {
10458
+ "path": "windSpeed",
10459
+ "valueType": "number"
10460
+ },
10461
+ {
10462
+ "path": "windSpeedUnit",
10463
+ "valueType": "string"
10464
+ },
10465
+ {
10466
+ "path": "windBearing",
10467
+ "valueType": "number"
10468
+ }
10469
+ ],
10470
+ "zone-analytics": [
10471
+ {
10472
+ "path": "ts",
10473
+ "valueType": "number"
10474
+ },
10475
+ {
10476
+ "path": "frameWidth",
10477
+ "valueType": "number"
10478
+ },
10479
+ {
10480
+ "path": "frameHeight",
10481
+ "valueType": "number"
10482
+ },
10483
+ {
10484
+ "path": "frame.totalObjects",
10485
+ "valueType": "number"
10486
+ },
10487
+ {
10488
+ "path": "frame.standingObjects",
10489
+ "valueType": "number"
10490
+ },
10491
+ {
10492
+ "path": "frame.transientObjects",
10493
+ "valueType": "number"
10494
+ },
10495
+ {
10496
+ "path": "unzoned.totalObjects",
10497
+ "valueType": "number"
10498
+ },
10499
+ {
10500
+ "path": "unzoned.standingObjects",
10501
+ "valueType": "number"
10502
+ },
10503
+ {
10504
+ "path": "unzoned.transientObjects",
10505
+ "valueType": "number"
10506
+ }
10507
+ ]
10508
+ });
8532
10509
  object({
8533
10510
  code: string().regex(/^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$/),
8534
10511
  params: record(string(), union([string(), number()])).optional()
@@ -8915,7 +10892,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
8915
10892
  return DeviceRole;
8916
10893
  }({});
8917
10894
  //#endregion
8918
- //#region ../types/dist/composition-CB6PMT9p.mjs
10895
+ //#region ../types/dist/composition-kEl9mevu.mjs
8919
10896
  /**
8920
10897
  * The ffmpeg build every CamStack node downloads, per platform and arch.
8921
10898
  *
@@ -8975,7 +10952,7 @@ portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac
8975
10952
  * ONE table for everyone who asks "is this device HIGH?": the
8976
10953
  * recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
8977
10954
  * sensor markers, the orchestrator's camera-sensors bridge and
8978
- * the sources of a composite doorbell (`doorbellFeatureSources`, D671).
10955
+ * the sources of a pulse (`compilePulseOverride`, D936).
8979
10956
  * A second copy would diverge at the first cap added, and the symptom — "the
8980
10957
  * sensor rings the doorbell but does not record" — is exactly D62.
8981
10958
  *
@@ -9216,6 +11193,20 @@ var table$1 = {
9216
11193
  apply: () => {
9217
11194
  throw new ExpressionEvalError("count: stateful evaluation context is required");
9218
11195
  }
11196
+ },
11197
+ dwell: {
11198
+ minArgs: 3,
11199
+ maxArgs: 3,
11200
+ apply: () => {
11201
+ throw new ExpressionEvalError("dwell: stateful evaluation context is required");
11202
+ }
11203
+ },
11204
+ latchedAt: {
11205
+ minArgs: 1,
11206
+ maxArgs: 1,
11207
+ apply: () => {
11208
+ throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
11209
+ }
9219
11210
  }
9220
11211
  };
9221
11212
  Object.freeze(Object.assign(Object.create(null), table$1));
@@ -10655,13 +12646,22 @@ var BirthDecisionRecordSchema = object({
10655
12646
  decidedByBirthEvidence: boolean(),
10656
12647
  /** Best class-compatible crop score, or `null` when nothing compatible was
10657
12648
  * found — deliberately not 0, which would be a measurement that never was.
10658
- * Includes a box the detector's own per-class floor refused (reason
10659
- * `below-detector-floor`, D922): that box never confirms, but it is the
10660
- * score the crop really held. */
12649
+ * Includes a box the detector's own per-class floor refused (D922): since
12650
+ * D925 the gate's bar, not that floor, decides whether it confirms. */
10661
12651
  bestScore: number().nullable(),
10662
12652
  /** The bar this candidate actually faced (the phantom-cell hook may raise it). */
10663
12653
  appliedMinConfidence: number().nullable(),
10664
12654
  /**
12655
+ * The detector the gate re-judged the birth WITH (D925): the session's own
12656
+ * root model, inference-device pool and node — never a node default. `null`
12657
+ * when the frame named no session detector or no gate ran, and on rows
12658
+ * written before D925. A `session-device-unavailable` row names the session
12659
+ * detector that could not be reached.
12660
+ */
12661
+ detectorModelId: string().nullable().default(null),
12662
+ detectorDeviceKey: string().nullable().default(null),
12663
+ detectorNodeId: string().nullable().default(null),
12664
+ /**
10665
12665
  * The track's own `firstSeen` — the candidate's first frame, which is where
10666
12666
  * the timeline starts. `null` for a suppressed birth, which has no track.
10667
12667
  */
@@ -12320,7 +14320,7 @@ var LogChannelDescriptorSchema = object({
12320
14320
  * `true` is a PROMISE with two halves, and both must hold: the gate is
12321
14321
  * consulted with the numeric device id, AND every line the channel admits
12322
14322
  * carries `tags: { deviceId }` with that same numeric id. The second half is
12323
- * what makes `| json | deviceId="617"` work in Loki — `loki-payload.ts`
14323
+ * what makes `| json | deviceId="102"` work in Loki — `loki-payload.ts`
12324
14324
  * keeps `deviceId` out of the stream labels for cardinality, so the tag in
12325
14325
  * the body is the only way to filter.
12326
14326
  *
@@ -12865,7 +14865,7 @@ var ModelVariantGroupSchema = object({
12865
14865
  precision: _enum(["fp32", "int8"]).optional(),
12866
14866
  /**
12867
14867
  * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
12868
- * an alternate training of the same family (Scrypted `relu_test`); chip
14868
+ * an alternate training of the same family (plugin catalog `relu_test`); chip
12869
14869
  * label is "Test".
12870
14870
  */
12871
14871
  optimization: _enum(["standard", "test"]).optional(),
@@ -13117,8 +15117,8 @@ var ModelCatalogEntrySchema = object({
13117
15117
  provider: ModelProviderIdSchema.optional(),
13118
15118
  /**
13119
15119
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
13120
- * applies (Frigate / COCO public catalog). Set on a custom model whose raw
13121
- * labels already ARE the CamStack macros (Scrypted identity map).
15120
+ * applies (plus catalog / COCO public catalog). Set on a custom model whose raw
15121
+ * labels already ARE the CamStack macros (plugin catalog identity map).
13122
15122
  */
13123
15123
  classMap: DetectionCatalogClassMapSchema.optional(),
13124
15124
  /**
@@ -16087,7 +18087,7 @@ method(object({
16087
18087
  * `1` is real time and is the ONLY value that allows the copy branch —
16088
18088
  * anything else forces `libx264` over the window. That was priced
16089
18089
  * before it was chosen: a per-event burst measured at 0.23 s and 254 KB
16090
- * on a real 615 720p cut, against 922 KB for the copy it replaces. A
18090
+ * on a real 101 720p cut, against 922 KB for the copy it replaces. A
16091
18091
  * re-encode is capped at 720p (`EVENT_CLIP_ENCODE_MAX_WIDTH`), because
16092
18092
  * once the decode is forced the width stops being free.
16093
18093
  */
@@ -16613,6 +18613,7 @@ var CompositionRunStatusSchema = _enum([
16613
18613
  "starting",
16614
18614
  "running",
16615
18615
  "degraded",
18616
+ "incomplete",
16616
18617
  "failed"
16617
18618
  ]);
16618
18619
  var CompositionFieldStateKindSchema = _enum([
@@ -16662,6 +18663,13 @@ var ComposerUnreadableBlockSchema = object({
16662
18663
  /** The parse error, in the operator's words. */
16663
18664
  error: string()
16664
18665
  });
18666
+ /** A confirmed release the hub did not accept. `deviceId` is the claim's device. */
18667
+ var UnreleasedClaimSchema = object({
18668
+ deviceId: number().int(),
18669
+ capName: string(),
18670
+ owner: string(),
18671
+ error: string()
18672
+ });
16665
18673
  method(object({
16666
18674
  /** The shared Blocks integration; null until `core-blocks` has reconciled it. */
16667
18675
  integrationId: string().nullable(),
@@ -16671,7 +18679,13 @@ method(object({
16671
18679
  /** Operator restarts: rebuild these runtimes and re-resolve their sources. Stores nothing (D62). */
16672
18680
  restartBlockIds: array(string()),
16673
18681
  /** Composition rows that exist but do not parse: held, never withdrawn, reported failed. */
16674
- unreadableBlocks: array(ComposerUnreadableBlockSchema)
18682
+ unreadableBlocks: array(ComposerUnreadableBlockSchema),
18683
+ /**
18684
+ * Operator-confirmed deletions. Their claims are released on this apply,
18685
+ * before any replacement block claims. A block that merely vanished from the
18686
+ * snapshot is not listed here and still waits for two applies (D49).
18687
+ */
18688
+ retiredBlockIds: array(string()).optional()
16675
18689
  }), object({
16676
18690
  blocks: array(object({
16677
18691
  blockId: string(),
@@ -16683,7 +18697,13 @@ method(object({
16683
18697
  * integration unknown, its own rows unread or read empty once). An empty
16684
18698
  * apply the caller owes is paid off only by one the composer acted on (D49).
16685
18699
  */
16686
- acted: boolean()
18700
+ acted: boolean(),
18701
+ /**
18702
+ * Confirmed releases this apply tried and the hub did not accept. Empty when
18703
+ * every one landed (or there was nothing to hand back). Absent on a result
18704
+ * that never got that far.
18705
+ */
18706
+ unreleasedClaims: array(UnreleasedClaimSchema).optional()
16687
18707
  }), {
16688
18708
  kind: "mutation",
16689
18709
  auth: "admin"
@@ -16726,7 +18746,15 @@ Object.freeze({
16726
18746
  kind: "fixed",
16727
18747
  result: ["number", "null"]
16728
18748
  },
16729
- count: NUMBER
18749
+ count: NUMBER,
18750
+ dwell: {
18751
+ kind: "fixed",
18752
+ result: ["boolean", "null"]
18753
+ },
18754
+ latchedAt: {
18755
+ kind: "fixed",
18756
+ result: ["number", "null"]
18757
+ }
16730
18758
  });
16731
18759
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
16732
18760
  /**
@@ -16799,6 +18827,7 @@ var CoreBlockStatusSchema = _enum([
16799
18827
  "starting",
16800
18828
  "running",
16801
18829
  "degraded",
18830
+ "incomplete",
16802
18831
  "failed"
16803
18832
  ]);
16804
18833
  /** path → TypeScript source for a multi-file block. */
@@ -38946,7 +40975,7 @@ var PRIMARY_CATEGORIES = new Set(ENTRIES.map((e) => e.primaryCategory));
38946
40975
  * `locationKey` is ALWAYS {@link locationIconKey} of the label — never the
38947
40976
  * operator's casing. The registry matches labels trimmed + case-insensitively
38948
40977
  * everywhere (`addLocation`, `removeLocation`, `renameLocation`), and a
38949
- * case-only rename (`cucina` → `Cucina`) is a real edit this repo supports; a
40978
+ * case-only rename (`kitchen` → `Kitchen`) is a real edit this repo supports; a
38950
40979
  * map keyed on the displayed casing would orphan its entry on exactly that
38951
40980
  * edit. Consumers join by keying their own label through `locationIconKey`.
38952
40981
  */
@@ -38971,7 +41000,7 @@ var LocationDescriptionAssignmentSchema = object({
38971
41000
  /**
38972
41001
  * A SITE ZONE — a named part of the property that several locations belong to.
38973
41002
  *
38974
- * "Zona notte" holds every bedroom; "Zona giorno" the living room and the
41003
+ * "Night zone" holds every bedroom; "Zona giorno" the living room and the
38975
41004
  * kitchen. A camera belongs to exactly one location, and a location to at most
38976
41005
  * one zone, so a camera's zone is derived and never stored on the device: the
38977
41006
  * whole point of this entity is that grouping rooms touches no device row.
@@ -39000,7 +41029,7 @@ var LocationDescriptionAssignmentSchema = object({
39000
41029
  * the locations inside it.
39001
41030
  *
39002
41031
  * The LABEL is carried alongside the key because the key is lossy on purpose —
39003
- * a surface must show "Zona notte", not "zona notte". Locations are carried
41032
+ * a surface must show "Night zone", not "night zone". Locations are carried
39004
41033
  * here, rather than left to a second call, because every consumer wants both
39005
41034
  * at once and a viewer that asked twice could render a zone whose membership
39006
41035
  * it has not fetched yet.
@@ -41213,8 +43242,8 @@ var LoadContributionSchema = object({
41213
43242
  "unattributable"
41214
43243
  ]),
41215
43244
  /**
41216
- * What ONE entry is, in the contributor's own words — `615/high`,
41217
- * `617/native`, `cuda:0 shared pool`. Free text because the unit differs per
43245
+ * What ONE entry is, in the contributor's own words — `101/high`,
43246
+ * `102/native`, `cuda:0 shared pool`. Free text because the unit differs per
41218
43247
  * family and inventing a common one would lose the only information that
41219
43248
  * makes two entries for the same camera distinguishable.
41220
43249
  */
@@ -42883,6 +44912,381 @@ var _macroLookup = /* @__PURE__ */ new Map();
42883
44912
  for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
42884
44913
  for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
42885
44914
  /**
44915
+ * Palette entry ids (D939). Audio is the one gradient; `audio-*` leaves are
44916
+ * not entries. `heatmapScrub` is a mark, not an event kind.
44917
+ */
44918
+ var PALETTE_ENTRY_IDS = [
44919
+ "motion",
44920
+ "audio",
44921
+ "recording",
44922
+ "live",
44923
+ "heatmapScrub",
44924
+ "person",
44925
+ "vehicle",
44926
+ "animal",
44927
+ "package",
44928
+ "sensor",
44929
+ "control",
44930
+ "face",
44931
+ "plate",
44932
+ "car",
44933
+ "truck",
44934
+ "bus",
44935
+ "motorcycle",
44936
+ "bicycle",
44937
+ "airplane",
44938
+ "boat",
44939
+ "train",
44940
+ "bird",
44941
+ "dog",
44942
+ "cat",
44943
+ "horse",
44944
+ "sheep",
44945
+ "cow",
44946
+ "elephant",
44947
+ "bear",
44948
+ "zebra",
44949
+ "giraffe",
44950
+ "package-delivered",
44951
+ "package-picked-up",
44952
+ "suitcase",
44953
+ "backpack",
44954
+ "handbag",
44955
+ "contact",
44956
+ "motion-sensor",
44957
+ "smoke",
44958
+ "flood",
44959
+ "gas",
44960
+ "carbon-monoxide",
44961
+ "vibration",
44962
+ "tamper",
44963
+ "presence",
44964
+ "enum-sensor",
44965
+ "device-event",
44966
+ "lock",
44967
+ "cover",
44968
+ "switch",
44969
+ "siren",
44970
+ "button",
44971
+ "doorbell"
44972
+ ];
44973
+ var AUDIO_ENTRY_ID = "audio";
44974
+ /** Six rungs, quiet → loud. The opaque end is the entry's hex. */
44975
+ var AUDIO_GRADIENT_ALPHAS = [
44976
+ .3,
44977
+ .42,
44978
+ .55,
44979
+ .7,
44980
+ .85,
44981
+ 1
44982
+ ];
44983
+ var PALETTE_PRESET_IDS = [
44984
+ "camstack",
44985
+ "high-contrast",
44986
+ "okabe-ito"
44987
+ ];
44988
+ /** Frozen palette tables (D939). The spec refuses a table that breaks the rule. */
44989
+ var CAMSTACK_HEX = {
44990
+ motion: "#d946ef",
44991
+ audio: "#059eb8",
44992
+ recording: "#ef4444",
44993
+ live: "#8d7a00",
44994
+ heatmapScrub: "#4b32ff",
44995
+ person: "#11a64c",
44996
+ vehicle: "#3b82f6",
44997
+ animal: "#ea6a09",
44998
+ package: "#924667",
44999
+ sensor: "#624bbc",
45000
+ control: "#944d24",
45001
+ face: "#ed4f8d",
45002
+ plate: "#4b7027",
45003
+ car: "#9684cf",
45004
+ truck: "#0f9b89",
45005
+ bus: "#a734a9",
45006
+ motorcycle: "#c1133a",
45007
+ bicycle: "#0e6a9b",
45008
+ airplane: "#7c9928",
45009
+ boat: "#b17933",
45010
+ train: "#ad6ca3",
45011
+ bird: "#0f7c55",
45012
+ dog: "#c82700",
45013
+ cat: "#7268f2",
45014
+ horse: "#cb795e",
45015
+ sheep: "#b8636b",
45016
+ cow: "#cb2969",
45017
+ elephant: "#1158d2",
45018
+ bear: "#8d5e00",
45019
+ zebra: "#0097d6",
45020
+ giraffe: "#8f61bb",
45021
+ "package-delivered": "#cd3f9b",
45022
+ "package-picked-up": "#388a08",
45023
+ suitcase: "#666800",
45024
+ backpack: "#ec5022",
45025
+ handbag: "#a76ef8",
45026
+ contact: "#ab5a49",
45027
+ "motion-sensor": "#b95d1a",
45028
+ smoke: "#dd3858",
45029
+ flood: "#b31e7d",
45030
+ gas: "#5b70b5",
45031
+ "carbon-monoxide": "#7b4e8e",
45032
+ vibration: "#e65bba",
45033
+ tamper: "#98464b",
45034
+ presence: "#3a9468",
45035
+ "enum-sensor": "#7885f8",
45036
+ "device-event": "#8c43c8",
45037
+ lock: "#649653",
45038
+ cover: "#c67597",
45039
+ switch: "#7a812a",
45040
+ siren: "#ac5d7f",
45041
+ button: "#b276cd",
45042
+ doorbell: "#0087ab"
45043
+ };
45044
+ var CAMSTACK_FALLBACK = [
45045
+ "#b34dc7",
45046
+ "#1d7d34",
45047
+ "#db6b6c",
45048
+ "#a43d29",
45049
+ "#0e6ee6",
45050
+ "#29a10b",
45051
+ "#a98731",
45052
+ "#0181c6"
45053
+ ];
45054
+ var HIGH_CONTRAST_HEX = {
45055
+ motion: "#964360",
45056
+ audio: "#23a132",
45057
+ recording: "#2494ca",
45058
+ live: "#bd7e2b",
45059
+ heatmapScrub: "#ad6eea",
45060
+ person: "#62611e",
45061
+ vehicle: "#f4534c",
45062
+ animal: "#1556cd",
45063
+ package: "#9c4415",
45064
+ sensor: "#066c48",
45065
+ control: "#f2479f",
45066
+ face: "#139d8a",
45067
+ plate: "#909024",
45068
+ car: "#8e35ab",
45069
+ truck: "#bd0b2b",
45070
+ bus: "#7a88ca",
45071
+ motorcycle: "#e26725",
45072
+ bicycle: "#a6679b",
45073
+ airplane: "#7c5720",
45074
+ boat: "#467a1b",
45075
+ train: "#6f65a4",
45076
+ bird: "#cb717f",
45077
+ dog: "#c62490",
45078
+ cat: "#b36850",
45079
+ horse: "#1872ac",
45080
+ sheep: "#927939",
45081
+ cow: "#428a5c",
45082
+ elephant: "#d41160",
45083
+ bear: "#799453",
45084
+ zebra: "#a85455",
45085
+ giraffe: "#746be8",
45086
+ "package-delivered": "#824a80",
45087
+ "package-picked-up": "#614ac1",
45088
+ suitcase: "#2f77f3",
45089
+ backpack: "#fa476d",
45090
+ handbag: "#c14cbe",
45091
+ contact: "#c83921",
45092
+ "motion-sensor": "#a07ebd",
45093
+ smoke: "#a25b13",
45094
+ flood: "#526bab",
45095
+ gas: "#924938",
45096
+ "carbon-monoxide": "#bb7e53",
45097
+ vibration: "#b66182",
45098
+ tamper: "#3c6931",
45099
+ presence: "#6c851d",
45100
+ "enum-sensor": "#ad2d48",
45101
+ "device-event": "#5e9b04",
45102
+ lock: "#00a062",
45103
+ cover: "#ad8624",
45104
+ switch: "#d05259",
45105
+ siren: "#cd67b3",
45106
+ button: "#c9746a",
45107
+ doorbell: "#338eeb"
45108
+ };
45109
+ var HIGH_CONTRAST_FALLBACK = [
45110
+ "#817f3b",
45111
+ "#a0733e",
45112
+ "#8658b2",
45113
+ "#956301",
45114
+ "#bc652d",
45115
+ "#647331",
45116
+ "#a14c9e",
45117
+ "#d14e71"
45118
+ ];
45119
+ var OKABE_ITO_HEX = {
45120
+ motion: "#b88128",
45121
+ audio: "#1096c8",
45122
+ recording: "#009e73",
45123
+ live: "#9c8c22",
45124
+ heatmapScrub: "#0072b2",
45125
+ person: "#d55e00",
45126
+ vehicle: "#c0739f",
45127
+ animal: "#226d18",
45128
+ package: "#91446c",
45129
+ sensor: "#217b56",
45130
+ control: "#648647",
45131
+ face: "#c22998",
45132
+ plate: "#fa4575",
45133
+ car: "#956301",
45134
+ truck: "#2f77f3",
45135
+ bus: "#7a4e86",
45136
+ motorcycle: "#f54597",
45137
+ bicycle: "#bb3e75",
45138
+ airplane: "#e054c0",
45139
+ boat: "#457942",
45140
+ train: "#867afa",
45141
+ bird: "#88914c",
45142
+ dog: "#1556cd",
45143
+ cat: "#71702c",
45144
+ horse: "#9b4fa4",
45145
+ sheep: "#c0559d",
45146
+ cow: "#d14f65",
45147
+ elephant: "#98470f",
45148
+ bear: "#595896",
45149
+ zebra: "#96790e",
45150
+ giraffe: "#cb717b",
45151
+ "package-delivered": "#139d8a",
45152
+ "package-picked-up": "#906ead",
45153
+ suitcase: "#d02939",
45154
+ backpack: "#d41160",
45155
+ handbag: "#f64f54",
45156
+ contact: "#7258d2",
45157
+ "motion-sensor": "#b66182",
45158
+ smoke: "#627abb",
45159
+ flood: "#b86ae4",
45160
+ gas: "#a95261",
45161
+ "carbon-monoxide": "#c65d3c",
45162
+ vibration: "#7a40b7",
45163
+ tamper: "#914b34",
45164
+ presence: "#9481c3",
45165
+ "enum-sensor": "#ac6d47",
45166
+ "device-event": "#7b6fce",
45167
+ lock: "#c67662",
45168
+ cover: "#a6564d",
45169
+ switch: "#ad2c4e",
45170
+ siren: "#348e08",
45171
+ button: "#d27303",
45172
+ doorbell: "#55770f"
45173
+ };
45174
+ var OKABE_ITO_FALLBACK = [
45175
+ "#9a3784",
45176
+ "#a7392c",
45177
+ "#409d50",
45178
+ "#6987e7",
45179
+ "#ee5b3d",
45180
+ "#c0430d",
45181
+ "#af79b3",
45182
+ "#4b6628"
45183
+ ];
45184
+ /**
45185
+ * The display palette (D939). One table of colours, three presets, one
45186
+ * validator. Taxonomy colours and every consumer read this — there is no
45187
+ * second hex table.
45188
+ */
45189
+ var paletteHexSchema = string().regex(/^#[0-9a-f]{6}$/);
45190
+ var paletteSwatchSchema = discriminatedUnion("form", [object({
45191
+ form: literal("solid"),
45192
+ hex: paletteHexSchema
45193
+ }), object({
45194
+ form: literal("gradient"),
45195
+ hex: paletteHexSchema,
45196
+ alphas: array(number().gt(0).lte(1)).length(AUDIO_GRADIENT_ALPHAS.length)
45197
+ })]);
45198
+ var paletteReadySchema = object({
45199
+ status: literal("ready"),
45200
+ presetId: _enum(PALETTE_PRESET_IDS),
45201
+ customized: boolean(),
45202
+ source: _enum(["stored", "unconfigured"]),
45203
+ swatches: record(string(), paletteSwatchSchema),
45204
+ fallbacks: array(paletteHexSchema).length(8)
45205
+ });
45206
+ var paletteResultSchema = discriminatedUnion("status", [paletteReadySchema, object({
45207
+ status: literal("unknown"),
45208
+ reason: string()
45209
+ })]);
45210
+ var setPaletteInputSchema = union([object({ presetId: string() }), object({
45211
+ presetId: string(),
45212
+ overrides: record(string(), paletteSwatchSchema)
45213
+ })]);
45214
+ object({
45215
+ presetId: string(),
45216
+ overrides: record(string(), paletteSwatchSchema)
45217
+ });
45218
+ function solid(hex) {
45219
+ return {
45220
+ form: "solid",
45221
+ hex
45222
+ };
45223
+ }
45224
+ function audioGradient(hex) {
45225
+ return {
45226
+ form: "gradient",
45227
+ hex,
45228
+ alphas: [...AUDIO_GRADIENT_ALPHAS]
45229
+ };
45230
+ }
45231
+ function swatchesFrom(hexes) {
45232
+ const out = {};
45233
+ for (const id of PALETTE_ENTRY_IDS) {
45234
+ const hex = hexes[id];
45235
+ if (hex === void 0) throw new Error(`palette table missing ${id}`);
45236
+ out[id] = id === "audio" ? audioGradient(hex) : solid(hex);
45237
+ }
45238
+ return out;
45239
+ }
45240
+ function preset(id, name, hexes, fallbacks) {
45241
+ return {
45242
+ id,
45243
+ name,
45244
+ swatches: swatchesFrom(hexes),
45245
+ fallbacks
45246
+ };
45247
+ }
45248
+ var DISPLAY_PRESETS = [
45249
+ preset("camstack", "CamStack", CAMSTACK_HEX, CAMSTACK_FALLBACK),
45250
+ preset("high-contrast", "High contrast", HIGH_CONTRAST_HEX, HIGH_CONTRAST_FALLBACK),
45251
+ preset("okabe-ito", "Colour-blind safe", OKABE_ITO_HEX, OKABE_ITO_FALLBACK)
45252
+ ];
45253
+ function presetById(id) {
45254
+ return DISPLAY_PRESETS.find((item) => item.id === id);
45255
+ }
45256
+ function bundledCamstack() {
45257
+ const presetRow = presetById("camstack");
45258
+ if (presetRow === void 0) throw new Error("CamStack preset missing");
45259
+ return readyOf(presetRow, "unconfigured", false);
45260
+ }
45261
+ function readyOf(row, source, customized) {
45262
+ return {
45263
+ status: "ready",
45264
+ presetId: row.id,
45265
+ customized,
45266
+ source,
45267
+ swatches: row.swatches,
45268
+ fallbacks: [...row.fallbacks]
45269
+ };
45270
+ }
45271
+ function hashFallback(kind, fallbacks) {
45272
+ let hash = 0;
45273
+ for (let i = 0; i < kind.length; i++) hash = hash * 31 + (kind.codePointAt(i) ?? 0) >>> 0;
45274
+ const hex = fallbacks[hash % fallbacks.length];
45275
+ if (hex === void 0) throw new Error("display palette has no fallback colour");
45276
+ return hex;
45277
+ }
45278
+ /** Colour a kind paints with. Audio leaves share the audio gradient's hex. */
45279
+ function paintHex(swatches, fallbacks, kind) {
45280
+ const key = kind.trim().toLowerCase();
45281
+ if (key.startsWith("audio-")) {
45282
+ const audio = swatches[AUDIO_ENTRY_ID];
45283
+ return audio !== void 0 ? audio.hex : hashFallback(key, fallbacks);
45284
+ }
45285
+ const direct = swatches[key];
45286
+ if (direct !== void 0) return direct.hex;
45287
+ return hashFallback(key, fallbacks);
45288
+ }
45289
+ /**
42886
45290
  * Unified event-kind taxonomy — THE single source of truth for
42887
45291
  * `kind → { parentKind, category, level, color, iconId, labelKey, label,
42888
45292
  * icon }`.
@@ -42896,109 +45300,88 @@ for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set
42896
45300
  * - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
42897
45301
  * - the COCO / audio class maps (macro ↔ sub relationships)
42898
45302
  *
42899
- * The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
42900
- * `@camstack/types`. The UI-side mapping `iconId → lucide component` and
42901
- * `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
42902
- * color or an icon: they read this dictionary (server descriptors carry the
42903
- * fields inline; the client resolves color/icon/label from `iconId`/`kind`).
45303
+ * The DATA (serializable — parentKind / iconId / labelKey) lives here in
45304
+ * `@camstack/types`. Colour is NOT a second table: each entry's `color` is
45305
+ * the bundled CamStack display palette (D939). The effective cluster palette
45306
+ * is the `display-palette` capability. The UI-side mapping `iconId → lucide
45307
+ * component` and `labelKey → t()` lives in `@camstack/ui-library`.
42904
45308
  *
42905
45309
  * Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
42906
45310
  */
42907
- var TAXONOMY_COLORS = {
42908
- motion: "#f59e0b",
42909
- audio: "#06b6d4",
42910
- person: "#22c55e",
42911
- vehicle: "#3b82f6",
42912
- animal: "#f97316",
42913
- package: "#a855f7",
42914
- sensor: "#8b5cf6",
42915
- control: "#10b981",
42916
- genericDetection: "#64748b"
42917
- };
42918
- var DETECTION_SUB_COLORS = {
42919
- car: "#f59e0b",
42920
- truck: "#d97706",
42921
- bus: "#b45309",
42922
- motorcycle: "#eab308",
42923
- bicycle: "#ca8a04",
42924
- airplane: "#60a5fa",
42925
- boat: "#2563eb",
42926
- train: "#1d4ed8",
42927
- bird: "#14b8a6",
42928
- dog: "#84cc16",
42929
- cat: "#f97316",
42930
- horse: "#a16207",
42931
- sheep: "#a3a3a3",
42932
- cow: "#78716c",
42933
- elephant: "#6b7280",
42934
- bear: "#7c2d12",
42935
- zebra: "#404040",
42936
- giraffe: "#d4a373"
42937
- };
45311
+ var BUNDLED_PALETTE = bundledCamstack();
45312
+ function kindColor(kind) {
45313
+ return paintHex(BUNDLED_PALETTE.swatches, BUNDLED_PALETTE.fallbacks, kind);
45314
+ }
45315
+ function firstFallback(fallbacks) {
45316
+ const hex = fallbacks[0];
45317
+ if (hex === void 0) throw new Error("display palette has no fallback colour");
45318
+ return hex;
45319
+ }
45320
+ firstFallback(BUNDLED_PALETTE.fallbacks);
42938
45321
  function titleCase(id) {
42939
45322
  return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
42940
45323
  }
42941
45324
  var entries = /* @__PURE__ */ new Map();
42942
- function macro(kind, category, color, iconId, label) {
45325
+ function macro(kind, category, iconId, label) {
42943
45326
  entries.set(kind, {
42944
45327
  kind,
42945
45328
  parentKind: null,
42946
45329
  level: "macro",
42947
45330
  category,
42948
- color,
45331
+ color: kindColor(kind),
42949
45332
  iconId,
42950
45333
  labelKey: `eventKind.${kind}`,
42951
45334
  label
42952
45335
  });
42953
45336
  }
42954
- function sub(kind, parentKind, category, color, iconId, label) {
45337
+ function sub(kind, parentKind, category, iconId, label) {
42955
45338
  entries.set(kind, {
42956
45339
  kind,
42957
45340
  parentKind,
42958
45341
  level: "sub",
42959
45342
  category,
42960
- color,
45343
+ color: kindColor(kind),
42961
45344
  iconId,
42962
45345
  labelKey: `eventKind.${kind}`,
42963
45346
  label
42964
45347
  });
42965
45348
  }
42966
- macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
42967
- macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
42968
- macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
42969
- macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
42970
- macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
42971
- macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
42972
- macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
42973
- macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
45349
+ macro("motion", "motion", "motion", "Motion");
45350
+ macro("audio", "audio", "audio", "Audio");
45351
+ macro("person", "detection", "person", "Person");
45352
+ macro("vehicle", "detection", "vehicle", "Vehicle");
45353
+ macro("animal", "detection", "animal", "Animal");
45354
+ macro("package", "package", "package", "Package");
45355
+ macro("sensor", "sensor", "sensor", "Sensor");
45356
+ macro("control", "control", "control", "Control");
42974
45357
  for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
42975
45358
  if (macroClass !== "vehicle" && macroClass !== "animal") continue;
42976
45359
  if (entries.has(cocoClass)) continue;
42977
- sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
42978
- }
42979
- sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
42980
- sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
42981
- sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
42982
- sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
42983
- sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
42984
- sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
42985
- sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
42986
- sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
42987
- sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
42988
- sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
42989
- sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
42990
- sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
42991
- sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
42992
- sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
42993
- sub("cover", "control", "control", "#0ea5e9", "door", "Cover");
42994
- sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
42995
- sub("siren", "control", "control", "#dc2626", "siren", "Siren");
42996
- sub("button", "control", "control", "#10b981", "button", "Button");
42997
- sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
45360
+ sub(cocoClass, macroClass, "detection", cocoClass, titleCase(cocoClass));
45361
+ }
45362
+ sub("package-delivered", "package", "package", "package", "Package delivered");
45363
+ sub("package-picked-up", "package", "package", "package", "Package picked up");
45364
+ sub("contact", "sensor", "sensor", "door", "Contact");
45365
+ sub("motion-sensor", "sensor", "sensor", "pir", "Motion sensor");
45366
+ sub("smoke", "sensor", "sensor", "smoke", "Smoke");
45367
+ sub("flood", "sensor", "sensor", "water", "Water leak");
45368
+ sub("gas", "sensor", "sensor", "gas", "Gas");
45369
+ sub("carbon-monoxide", "sensor", "sensor", "smoke", "Carbon monoxide");
45370
+ sub("vibration", "sensor", "sensor", "vibration", "Vibration");
45371
+ sub("tamper", "sensor", "sensor", "tamper", "Tamper");
45372
+ sub("presence", "sensor", "sensor", "presence", "Presence");
45373
+ sub("enum-sensor", "sensor", "sensor", "generic", "Sensor state");
45374
+ sub("device-event", "sensor", "sensor", "button", "Device event");
45375
+ sub("lock", "control", "control", "lock", "Lock");
45376
+ sub("cover", "control", "control", "door", "Cover");
45377
+ sub("switch", "control", "control", "switch", "Switch");
45378
+ sub("siren", "control", "control", "siren", "Siren");
45379
+ sub("button", "control", "control", "button", "Button");
45380
+ sub("doorbell", "control", "control", "doorbell", "Doorbell");
42998
45381
  for (const l of AUDIO_MACRO_LABELS) {
42999
45382
  const kind = `audio-${l.id}`;
43000
45383
  if (entries.has(kind)) continue;
43001
- sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
45384
+ sub(kind, "audio", "audio", kind, l.name);
43002
45385
  }
43003
45386
  /** The complete taxonomy dictionary, keyed by kind. */
43004
45387
  var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
@@ -43309,9 +45692,6 @@ var NcSystemEventKindSchema = _enum([
43309
45692
  "device-battery-normal",
43310
45693
  "device-consumable-low",
43311
45694
  "device-consumable-normal",
43312
- "device-tank-low",
43313
- "device-tank-full",
43314
- "device-tank-normal",
43315
45695
  "stream-online",
43316
45696
  "stream-offline",
43317
45697
  "node-online",
@@ -43358,13 +45738,14 @@ var NcSystemEventKindSchema = _enum([
43358
45738
  "camera-enabled"
43359
45739
  ]);
43360
45740
  /** The legacy tail of {@link NcSystemEventKindSchema} — see its docblock. */
43361
- var NC_LEGACY_SYSTEM_EVENT_KINDS = new Set([
45741
+ var NC_LEGACY_SYSTEM_EVENT_KINDS = [
43362
45742
  "camera-online",
43363
45743
  "camera-offline",
43364
45744
  "camera-disabled",
43365
45745
  "camera-enabled"
43366
- ]);
43367
- NcSystemEventKindSchema.options.filter((kind) => !NC_LEGACY_SYSTEM_EVENT_KINDS.has(kind));
45746
+ ];
45747
+ var NC_LEGACY_SYSTEM_EVENT_KIND_SET = new Set(NC_LEGACY_SYSTEM_EVENT_KINDS);
45748
+ NcSystemEventKindSchema.options.filter((kind) => !NC_LEGACY_SYSTEM_EVENT_KIND_SET.has(kind));
43368
45749
  /**
43369
45750
  * The panel's transitions, as ONE list.
43370
45751
  *
@@ -43887,7 +46268,7 @@ var NcConditionsSchema = object({
43887
46268
  * with the list under it is worse than no switch (D62).
43888
46269
  *
43889
46270
  * MEMBERS ARE FACE-GALLERY `Identity.id`s (uuid), not display names. A name is
43890
- * renameable, and a rule authored on "Gianluca" went silently dark the moment
46271
+ * renameable, and a rule authored on "Alice" went silently dark the moment
43891
46272
  * the operator fixed the spelling. The id reaches the record on
43892
46273
  * `LabelAttribution.identityId`; the name is what the editor shows and what
43893
46274
  * `{{label}}` renders.
@@ -44438,7 +46819,7 @@ var NcRulePatchSchema = NcRuleInputSchema.partial().extend({
44438
46819
  * A rule scoped to one camera and one zone silently became a rule that
44439
46820
  * matches EVERY event on EVERY camera, and lost its `media` policy
44440
46821
  * (zoneCrop / gif / clip / frame) and its `priority` at the same time. Seen
44441
- * live on 2026-08-12: a rule scoped to device 617 fired on 590 and 615
46822
+ * live on 2026-08-12: a rule scoped to device 102 fired on 104 and 101
44442
46823
  * within a minute of a two-field patch.
44443
46824
  *
44444
46825
  * So every defaulted field is re-declared here WITHOUT its default. The
@@ -44483,18 +46864,11 @@ var NcRuleSchema = NcRuleInputSchema.extend({
44483
46864
  */
44484
46865
  disabledTargetIds: array(string()).default([])
44485
46866
  });
44486
- /**
44487
- * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
44488
- * report a still-true state. `addons` is the crash-looped addons only and
44489
- * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
44490
- * job is not an open state, and the alarm stays instant.
44491
- */
44492
46867
  var NcStateSummarySectionIdSchema = _enum([
44493
46868
  "device-state",
44494
46869
  "streams",
44495
46870
  "battery",
44496
46871
  "consumables",
44497
- "tanks",
44498
46872
  "detection-blind",
44499
46873
  "nodes",
44500
46874
  "addons",
@@ -45795,6 +48169,18 @@ Object.freeze({
45795
48169
  reason: "camera sensor mappings not loaded"
45796
48170
  });
45797
48171
  /**
48172
+ * What the vision model must answer before a package event is emitted
48173
+ * when a packages rule has "Confirm with the LLM" on.
48174
+ *
48175
+ * `package` is the verdict. `confidence` is 0..1. `reason` is the model's
48176
+ * one-line explanation, stored on the event so a drop is not silent.
48177
+ */
48178
+ var PackageLlmVerdictSchema = object({
48179
+ package: boolean(),
48180
+ confidence: number().min(0).max(1),
48181
+ reason: string().min(1)
48182
+ });
48183
+ /**
45798
48184
  * A model choice has a SCOPE, and a scope change has a workflow.
45799
48185
  *
45800
48186
  * ## The two scopes
@@ -46246,7 +48632,7 @@ var LabelAttributionSchema = object({
46246
48632
  * `Identity.id` or a plate-gallery `Vehicle.id` (both `randomUUID`).
46247
48633
  *
46248
48634
  * The text alone is a DISPLAY NAME, and a display name is renameable: a
46249
- * notification rule authored on "Gianluca" stopped matching the moment the
48635
+ * notification rule authored on "Alice" stopped matching the moment the
46250
48636
  * operator fixed the spelling in the gallery, and nothing said so. The id is
46251
48637
  * the thing that does not move, so it is what a rule matches on
46252
48638
  * (`NcConditions.identities`) and the text is what a human is shown.
@@ -46731,6 +49117,21 @@ var ObjectEventSchema = object({
46731
49117
  * pick-up written before D684 — UNKNOWN, never 0 and never `timestamp`.
46732
49118
  */
46733
49119
  observedAt: number().optional(),
49120
+ /**
49121
+ * The delivery was emitted without a vision-model yes (D931).
49122
+ *
49123
+ * Set only when the packages rule asked for an LLM confirm and the model
49124
+ * was unreachable, timed out, or answered something that did not parse.
49125
+ * A notification reads it so it can say "possible" instead of a definite
49126
+ * delivery. Absent on every other row, and on a confirm that said yes.
49127
+ */
49128
+ packagePossible: boolean().optional(),
49129
+ /**
49130
+ * The vision model's verdict, when a packages rule asked for one and the
49131
+ * model answered the schema (D931). A "no" never becomes a row — the
49132
+ * detector drops it and logs the reason. Present on a yes.
49133
+ */
49134
+ packageLlmVerdict: PackageLlmVerdictSchema.optional(),
46734
49135
  /** The parent track's key-event importance [0,1], propagated to every object
46735
49136
  * event of the track (so an event row can be sorted by importance without a
46736
49137
  * track join). Absent on legacy rows / before the track was scored. */
@@ -48528,7 +50929,6 @@ var PipelineAddonSchemaSchema = object({
48528
50929
  defaultModelId: string(),
48529
50930
  defaultModelIdByFormat: record(string(), string()).optional(),
48530
50931
  enabledByDefault: boolean().optional(),
48531
- backfillIntoExistingOverrides: boolean().optional(),
48532
50932
  defaultConfidence: number(),
48533
50933
  group: string().optional(),
48534
50934
  configSchema: array(ConfigFieldBridge).readonly().optional()
@@ -48655,13 +51055,12 @@ var AudioTestResultSchema = object({
48655
51055
  error: string().optional(),
48656
51056
  frame: custom().optional()
48657
51057
  });
48658
- var PipelineConfigBridge = custom();
48659
51058
  var ConfigUISchemaBridge = custom();
48660
51059
  var ConfigUISchemaNullableBridge = custom();
48661
51060
  var InferenceCapabilitiesBridge = custom();
48662
51061
  var ModelAvailabilityListBridge = custom();
48663
51062
  var PipelineRunResultBridge = custom();
48664
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
51063
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
48665
51064
  modelId: string(),
48666
51065
  settings: record(string(), unknown()).readonly()
48667
51066
  }))), method(object({ steps: record(string(), object({
@@ -48670,28 +51069,6 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
48670
51069
  })) }), object({ success: literal(true) }), {
48671
51070
  kind: "mutation",
48672
51071
  auth: "admin"
48673
- }), method(object({ nodeId: string() }), object({
48674
- success: literal(true),
48675
- clearedDevices: number()
48676
- }), {
48677
- kind: "mutation",
48678
- auth: "admin"
48679
- }), method(object({
48680
- nodeId: string(),
48681
- deviceIds: array(number()).readonly().optional(),
48682
- dryRun: boolean()
48683
- }), object({
48684
- entries: array(object({
48685
- deviceId: number(),
48686
- keys: array(string()).readonly()
48687
- })).readonly(),
48688
- refused: array(object({
48689
- deviceId: number(),
48690
- reason: string()
48691
- })).readonly()
48692
- }), {
48693
- kind: "mutation",
48694
- auth: "admin"
48695
51072
  }), method(object({ nodeId: string() }), object({ unhealthy: array(object({
48696
51073
  /** `<backend>:<device>`, e.g. `openvino:gpu`. */
48697
51074
  deviceKey: string(),
@@ -48714,7 +51091,7 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
48714
51091
  }), object({ rearmed: boolean() }), {
48715
51092
  kind: "mutation",
48716
51093
  auth: "admin"
48717
- }), method(_void(), PipelineSchemaSchema), method(_void(), array(PipelineDefaultStepSchema).readonly().nullable()), method(_void(), PipelineConfigBridge), method(_void(), ConfigUISchemaBridge), method(object({
51094
+ }), method(_void(), PipelineSchemaSchema), method(_void(), ConfigUISchemaBridge), method(object({
48718
51095
  steps: array(PipelineStepInputSchema),
48719
51096
  deviceKey: string().optional()
48720
51097
  }), PipelineValidationResultSchema), method(_void(), InferenceCapabilitiesBridge), method(object({ addonId: string() }), ModelAvailabilityListBridge), method(object({
@@ -48794,7 +51171,7 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
48794
51171
  /**
48795
51172
  * Root-supplied detections for the tree's ROOT step (D730). Set by
48796
51173
  * `runDetailSubtree` when the camera's root model supplies a crop-kind
48797
- * step (a Frigate+ `license_plate` for `plate-detection`): the step is
51174
+ * step (a plus catalog `license_plate` for `plate-detection`): the step is
48798
51175
  * NOT inferred, these boxes are its output, and its children (the plate
48799
51176
  * reader) run on them through their own crop policy. Boxes are in the
48800
51177
  * PIXELS of the image this call carries. Absent ⇒ the root step runs.
@@ -48962,11 +51339,18 @@ var KeptReasonSchema = _enum(["custom-pin"]);
48962
51339
  * Where a choice's latency came from (D791): this node's own benchmark
48963
51340
  * result, or the hardware-class table. Measured on the node beats the table.
48964
51341
  */
48965
- var LatencySourceSchema = discriminatedUnion("kind", [object({ kind: literal("table") }), object({
48966
- kind: literal("node-benchmark"),
48967
- resultId: string(),
48968
- measuredAtMs: number()
48969
- })]);
51342
+ var LatencySourceSchema = discriminatedUnion("kind", [
51343
+ object({ kind: literal("table") }),
51344
+ object({
51345
+ kind: literal("node-benchmark"),
51346
+ resultId: string(),
51347
+ measuredAtMs: number()
51348
+ }),
51349
+ object({
51350
+ kind: literal("estimated"),
51351
+ estimatedFrom: HardwareClassIdSchema
51352
+ })
51353
+ ]);
48970
51354
  var DeviceModelChoiceSchema = object({
48971
51355
  modelId: string(),
48972
51356
  p50Ms: number(),
@@ -48974,6 +51358,11 @@ var DeviceModelChoiceSchema = object({
48974
51358
  measured: boolean(),
48975
51359
  /** Absent on a plan from before D791 — read as the table. */
48976
51360
  source: LatencySourceSchema.optional(),
51361
+ /**
51362
+ * The measured class this latency was scaled from (D930). Absent when the
51363
+ * cell is the table or a node benchmark.
51364
+ */
51365
+ estimatedFrom: HardwareClassIdSchema.optional(),
48977
51366
  /** Parallel sessions at the camera rate with the headroom kept free: ⌊fps × (1 − headroom) / camera fps⌋. */
48978
51367
  capacitySessions: number(),
48979
51368
  personRecall: number()
@@ -49013,40 +51402,20 @@ var NodeDeviceChangeSchema = object({
49013
51402
  keys: array(string()).readonly()
49014
51403
  })).readonly()
49015
51404
  });
49016
- var CameraOverrideClearSchema = object({
49017
- deviceId: number(),
49018
- source: _enum(["step-override", "wholesale"]),
51405
+ /**
51406
+ * Every model and model-bound threshold lives on the accelerator that runs it
51407
+ * (D927), so the plan writes node / device entries only — there is no camera
51408
+ * layer for it to clear.
51409
+ */
51410
+ var AutoTuneWarningSchema = discriminatedUnion("kind", [object({
51411
+ kind: literal("custom-pin-kept"),
49019
51412
  nodeId: string(),
49020
- deviceKey: string().nullable(),
49021
- stepId: string(),
49022
- modelIdBefore: string().nullable(),
49023
- keys: array(string()).readonly()
49024
- });
49025
- var DetectorStoreClearSchema = object({
49026
- deviceId: number(),
49027
- keys: array(string()).readonly()
49028
- });
49029
- var AutoTuneWarningSchema = discriminatedUnion("kind", [
49030
- object({
49031
- kind: literal("detector-store-cluster-wide"),
49032
- skippedNodes: array(string()).readonly()
49033
- }),
49034
- object({
49035
- kind: literal("detector-store-unreadable"),
49036
- error: string()
49037
- }),
49038
- object({
49039
- kind: literal("custom-pin-kept"),
49040
- nodeId: string(),
49041
- deviceKey: string().nullable(),
49042
- deviceId: number().nullable(),
49043
- modelId: string()
49044
- }),
49045
- object({
49046
- kind: literal("custom-registry-unreadable"),
49047
- error: string()
49048
- })
49049
- ]);
51413
+ deviceKey: string(),
51414
+ modelId: string()
51415
+ }), object({
51416
+ kind: literal("custom-registry-unreadable"),
51417
+ error: string()
51418
+ })]);
49050
51419
  var AutoTuneOptionsSchema = object({
49051
51420
  /** Share of each accelerator's throughput kept free (0.3–0.5). */
49052
51421
  headroom: number().min(.3).max(.5).default(.4),
@@ -49068,8 +51437,6 @@ var AutoTunePlanSchema = object({
49068
51437
  generatedAt: number(),
49069
51438
  nodes: array(NodeRecommendationSchema).readonly(),
49070
51439
  nodeChanges: array(NodeDeviceChangeSchema).readonly(),
49071
- cameraClears: array(CameraOverrideClearSchema).readonly(),
49072
- detectorStoreClears: array(DetectorStoreClearSchema).readonly(),
49073
51440
  warnings: array(AutoTuneWarningSchema).readonly()
49074
51441
  });
49075
51442
  var AutoTuneApplyInputSchema = object({
@@ -49080,8 +51447,6 @@ var AutoTuneApplyInputSchema = object({
49080
51447
  var AutoTunePhaseResultSchema = object({
49081
51448
  phase: _enum([
49082
51449
  "download",
49083
- "camera-overrides",
49084
- "detector-thresholds",
49085
51450
  "node-models",
49086
51451
  "redispatch"
49087
51452
  ]),
@@ -50483,7 +52848,7 @@ var RunnerCameraConfigSchema = object({
50483
52848
  * detection session that asks for history. What shipped was a last-moment
50484
52849
  * discard — `FrameSlot`'s throttle compares wall clocks, and ~4 s of media
50485
52850
  * arriving inside a few hundred ms of wall clock looks to it like one frame's
50486
- * worth. Device 617, 2026-09-08: a re-run of the SAME model over the stored
52851
+ * worth. Device 102, 2026-09-08: a re-run of the SAME model over the stored
50487
52852
  * recording scored the subject `vehicle 0.5669` — above the 0.50 floor —
50488
52853
  * 1.68 s BEFORE the live track was born, on a frame that was in the pre-roll,
50489
52854
  * was decoded, and was freed.
@@ -50836,6 +53201,12 @@ var AgentPipelineSettingsSchema = object({
50836
53201
  /** Hub-persisted UI colour (`--color-node-*` theme tokens). */
50837
53202
  color: NodeColorIdSchema.optional(),
50838
53203
  /**
53204
+ * NODE-wide step settings (D927): `stepId → { key → value }`, applied on
53205
+ * every accelerator of the node under the device's own settings. Never a
53206
+ * model or a model-bound threshold. Written by `setNodeStepSettings`.
53207
+ */
53208
+ stepSettings: record(string(), record(string(), unknown()).readonly()).optional(),
53209
+ /**
50839
53210
  * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
50840
53211
  * weight, steps}. Absent / all-disabled ⇒ the node's single default
50841
53212
  * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
@@ -50851,17 +53222,6 @@ var AgentPipelineSettingsSchema = object({
50851
53222
  steps: record(string(), DeviceStepConfigSchema).optional()
50852
53223
  })).optional()
50853
53224
  });
50854
- var CameraPipelineForAgentSchema = object({
50855
- steps: array(PipelineStepInputSchema).readonly(),
50856
- audio: object({
50857
- modelId: string(),
50858
- enabled: boolean()
50859
- }).nullable()
50860
- });
50861
- var CameraStepOverridePatchSchema = object({
50862
- modelId: string().optional(),
50863
- settings: record(string(), unknown()).readonly().optional()
50864
- });
50865
53225
  var CameraStepSettingsSchema = record(string(), record(string(), unknown()).readonly());
50866
53226
  /** The three root-detector choices a camera has (D507: at most one root). */
50867
53227
  var CameraDetectionSourceSchema = _enum([
@@ -50871,9 +53231,7 @@ var CameraDetectionSourceSchema = _enum([
50871
53231
  ]);
50872
53232
  var CameraPipelineSettingsSchema = object({
50873
53233
  stepToggles: record(string(), boolean()).optional(),
50874
- stepSettings: CameraStepSettingsSchema.optional(),
50875
- stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
50876
- pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
53234
+ stepSettings: CameraStepSettingsSchema.optional()
50877
53235
  });
50878
53236
  /**
50879
53237
  * Pipeline placement record persisted by `addon-pipeline-orchestrator` via
@@ -51419,6 +53777,13 @@ method(object({
51419
53777
  }), object({ success: literal(true) }), {
51420
53778
  kind: "mutation",
51421
53779
  auth: "admin"
53780
+ }), method(object({
53781
+ agentNodeId: string(),
53782
+ addonId: string(),
53783
+ settings: record(string(), unknown()).nullable()
53784
+ }), object({ success: literal(true) }), {
53785
+ kind: "mutation",
53786
+ auth: "admin"
51422
53787
  }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({
51423
53788
  agentNodeId: string(),
51424
53789
  deviceKey: string()
@@ -51428,9 +53793,7 @@ method(object({
51428
53793
  }), method(object({ agentNodeId: string() }), object({
51429
53794
  success: literal(true),
51430
53795
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
51431
- effectiveModelId: string().nullable(),
51432
- /** Number of cameras whose node-scoped overrides were cleared. */
51433
- clearedCameraOverrides: number()
53796
+ effectiveModelId: string().nullable()
51434
53797
  }), {
51435
53798
  kind: "mutation",
51436
53799
  auth: "admin"
@@ -51485,15 +53848,6 @@ method(object({
51485
53848
  }), object({ success: literal(true) }), {
51486
53849
  kind: "mutation",
51487
53850
  auth: "admin"
51488
- }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
51489
- deviceId: number(),
51490
- agentNodeId: string(),
51491
- deviceKey: string(),
51492
- addonId: string(),
51493
- patch: CameraStepOverridePatchSchema.nullable()
51494
- }), object({ success: literal(true) }), {
51495
- kind: "mutation",
51496
- auth: "admin"
51497
53851
  }), method(object({
51498
53852
  deviceId: number(),
51499
53853
  addonId: string(),
@@ -51501,13 +53855,6 @@ method(object({
51501
53855
  }), object({ success: literal(true) }), {
51502
53856
  kind: "mutation",
51503
53857
  auth: "admin"
51504
- }), method(object({
51505
- deviceId: number(),
51506
- agentNodeId: string(),
51507
- pipeline: CameraPipelineForAgentSchema.nullable()
51508
- }), object({ success: literal(true) }), {
51509
- kind: "mutation",
51510
- auth: "admin"
51511
53858
  }), method(object({
51512
53859
  deviceId: number(),
51513
53860
  agentNodeId: string().optional()
@@ -52635,7 +54982,7 @@ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config:
52635
54982
  * The signals a device can emit to WAKE its own stream.
52636
54983
  *
52637
54984
  * A camera whose stream is built on demand sleeps until something asks for it,
52638
- * and "something" cannot be a consumer that is merely attached — a Frigate-style
54985
+ * and "something" cannot be a consumer that is merely attached — a external-catalog
52639
54986
  * puller holds a session open for ever, and treating that as demand would keep
52640
54987
  * a battery camera awake for ever, which is the whole thing the battery is for
52641
54988
  * (D173). So the wake has to come from the CAMERA: an event it noticed by
@@ -53403,7 +55750,7 @@ var ClipSchema = object({
53403
55750
  * {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
53404
55751
  *
53405
55752
  * Bounded because it is not a payload the surface pages through: one visit on
53406
- * device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
55753
+ * device 101 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
53407
55754
  * camera-day. Read {@link eventCount} for the true total.
53408
55755
  */
53409
55756
  eventIds: array(string()).optional(),
@@ -53548,7 +55895,7 @@ var ClipPlaybackSchema = object({
53548
55895
  * camera has no recordings", which is the defect this whole line of work is
53549
55896
  * about: a battery camera nobody woke (`sleeping`), a camera that could not be
53550
55897
  * reached at all (`unreachable`, also what a provider that THREW reports), a
53551
- * camera whose SD card is not mounted (`no-storage`, measured on 640 —
55898
+ * camera whose SD card is not mounted (`no-storage`, measured on 106 —
53552
55899
  * `HddInfo mount 0`, honestly nothing to list rather than "no clips"), and a
53553
55900
  * camera whose OWN index disagrees with its OWN calendar (`index-empty`,
53554
55901
  * measured on 618: the calendar marks 3–20 September, days 6–20 list zero
@@ -54009,7 +56356,7 @@ var videoclipsCapability = {
54009
56356
  *
54010
56357
  * It was optional, documented as "absent means the device's BOUND
54011
56358
  * provider, which is CamStack on every camera". No code implemented
54012
- * that. Measured on the live hub 2026-09-20 — device 592, bound to
56359
+ * that. Measured on the live hub 2026-09-20 — device 107, bound to
54013
56360
  * `recorder` AND `provider-reolink` — a bare call with `limit: 3`
54014
56361
  * answered SIX rows, three from each source, merged newest-first:
54015
56362
  * `device-collection-dispatch.ts` simply left the fan-out un-narrowed,
@@ -55326,7 +57673,10 @@ var airQualitySensorCapability = {
55326
57673
  */
55327
57674
  var AmbientLightSensorStatusSchema = object({
55328
57675
  /** Current illuminance in lux (lx). */
55329
- lux: number().min(0),
57676
+ lux: number().min(0).meta({
57677
+ unit: "lx",
57678
+ label: "Illuminance"
57679
+ }),
55330
57680
  /** Ms epoch when the slice was last updated. */
55331
57681
  lastFetchedAt: number(),
55332
57682
  /** Live display unit from the upstream source (e.g. HA
@@ -55369,7 +57719,12 @@ var ambientLightSensorCapability = {
55369
57719
  } } },
55370
57720
  /** Clock fields: written, but excluded from the compare that decides
55371
57721
  * whether persisting is worth a SQLite commit. */
55372
- volatileStateFields: ["lastFetchedAt"]
57722
+ volatileStateFields: ["lastFetchedAt"],
57723
+ customize: {
57724
+ version: 1,
57725
+ advanced: "derive",
57726
+ targets: []
57727
+ }
55373
57728
  };
55374
57729
  /**
55375
57730
  * Per-class audio metrics aggregated over a sliding window.
@@ -55596,7 +57951,10 @@ var BatteryStatusSchema = object({
55596
57951
  * Consumers must SKIP a null rather than coerce it — `battery-band` already
55597
57952
  * declines to band a non-finite reading, which is the correct shape.
55598
57953
  */
55599
- percentage: number().min(0).max(100).nullable(),
57954
+ percentage: number().min(0).max(100).nullable().meta({
57955
+ unit: "%",
57956
+ label: "Charge"
57957
+ }),
55600
57958
  /**
55601
57959
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
55602
57960
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -55615,13 +57973,13 @@ var BatteryStatusSchema = object({
55615
57973
  "solar",
55616
57974
  "none",
55617
57975
  "unknown"
55618
- ]),
57976
+ ]).meta({ label: "Charging source" }),
55619
57977
  /**
55620
57978
  * True when the camera firmware has gone into low-power mode. Battery
55621
57979
  * providers MUST avoid polling during sleep — reading the battery
55622
57980
  * wakes the camera up and drains charge.
55623
57981
  */
55624
- sleeping: boolean(),
57982
+ sleeping: boolean().meta({ label: "Sleeping" }),
55625
57983
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
55626
57984
  lastUpdated: number(),
55627
57985
  /**
@@ -55661,22 +58019,71 @@ var BatteryStatusSchema = object({
55661
58019
  * sub-threshold = low). UI MUST render "Normal"/"Low" instead of a
55662
58020
  * misleading exact percentage. Absent/false → genuine 0–100 % reading.
55663
58021
  */
55664
- binary: boolean().optional()
58022
+ binary: boolean().optional().meta({ label: "Binary indicator" })
55665
58023
  });
58024
+ var BATTERY_DEVICE_TYPES = [
58025
+ DeviceType.Camera,
58026
+ DeviceType.Sensor,
58027
+ DeviceType.Button,
58028
+ DeviceType.Switch,
58029
+ DeviceType.PetFeeder,
58030
+ DeviceType.Container,
58031
+ DeviceType.Thermostat
58032
+ ];
58033
+ /** Generic Customize target for the percentage reading (D936). */
58034
+ var batteryCustomize = {
58035
+ version: 1,
58036
+ advanced: "derive",
58037
+ targets: [{
58038
+ id: "percentage",
58039
+ cardinality: "scalar",
58040
+ vocabulary: {
58041
+ cap: "battery",
58042
+ stateField: "percentage"
58043
+ },
58044
+ deviceTypes: BATTERY_DEVICE_TYPES,
58045
+ apply: "add-or-replace",
58046
+ path: "percentage",
58047
+ sources: [{
58048
+ kind: "field",
58049
+ valueKinds: ["number", "string"],
58050
+ transforms: [{ kind: "identity" }, {
58051
+ kind: "linear",
58052
+ defaultScale: 1,
58053
+ defaultOffset: 0,
58054
+ clampMin: 0,
58055
+ clampMax: 100
58056
+ }]
58057
+ }],
58058
+ companions: [
58059
+ {
58060
+ kind: "constant",
58061
+ path: "charging",
58062
+ value: "unknown",
58063
+ when: "add"
58064
+ },
58065
+ {
58066
+ kind: "constant",
58067
+ path: "sleeping",
58068
+ value: false,
58069
+ when: "add"
58070
+ },
58071
+ {
58072
+ kind: "clock",
58073
+ path: "lastUpdated",
58074
+ when: "add"
58075
+ }
58076
+ ],
58077
+ sourceReport: { status: "assignment-status" },
58078
+ advancedExpression: true
58079
+ }]
58080
+ };
55666
58081
  var batteryCapability = {
55667
58082
  name: "battery",
55668
58083
  scope: "device",
55669
58084
  deviceNative: true,
55670
58085
  mode: "singleton",
55671
- deviceTypes: [
55672
- DeviceType.Camera,
55673
- DeviceType.Sensor,
55674
- DeviceType.Button,
55675
- DeviceType.Switch,
55676
- DeviceType.PetFeeder,
55677
- DeviceType.Container,
55678
- DeviceType.Thermostat
55679
- ],
58086
+ deviceTypes: BATTERY_DEVICE_TYPES,
55680
58087
  methods: {
55681
58088
  /**
55682
58089
  * Explicitly wake the camera from low-power sleep ahead of a
@@ -55760,6 +58167,7 @@ onStatusChanged: { data: object({
55760
58167
  kind: "gauge",
55761
58168
  unit: "%"
55762
58169
  } } },
58170
+ customize: batteryCustomize,
55763
58171
  /** Clock fields: written, but excluded from the compare that decides
55764
58172
  * whether persisting is worth a SQLite commit. */
55765
58173
  volatileStateFields: ["lastUpdated"]
@@ -55776,7 +58184,7 @@ onStatusChanged: { data: object({
55776
58184
  * with the right HomeKit / Alexa display category.
55777
58185
  */
55778
58186
  var BinaryStatusSchema = object({
55779
- on: boolean(),
58187
+ on: boolean().meta({ label: "On" }),
55780
58188
  /** Ms epoch of the last transition. 0 if never observed. */
55781
58189
  lastChangedAt: number()
55782
58190
  });
@@ -55805,7 +58213,12 @@ var binaryCapability = {
55805
58213
  history: { fields: { on: { kind: "boolean" } } },
55806
58214
  /** Clock fields: written, but excluded from the compare that decides
55807
58215
  * whether persisting is worth a SQLite commit. */
55808
- volatileStateFields: ["lastChangedAt"]
58216
+ volatileStateFields: ["lastChangedAt"],
58217
+ customize: {
58218
+ version: 1,
58219
+ advanced: "derive",
58220
+ targets: []
58221
+ }
55809
58222
  };
55810
58223
  /**
55811
58224
  * Dimmable-light brightness control. Co-exists with `switch` on the
@@ -56111,7 +58524,7 @@ var GridLayoutCellSchema = object({
56111
58524
  *
56112
58525
  * A grid's `high` composes its sources' `high` and its `low` their `low`, so a
56113
58526
  * profile is on offer only when EVERY source can serve it. The refusal NAMES
56114
- * the sources, because "this grid has no low" is not a finding — "615 has no
58527
+ * the sources, because "this grid has no low" is not a finding — "101 has no
56115
58528
  * low" is, and it is the one an operator can act on.
56116
58529
  */
56117
58530
  var GridProfileOfferSchema = object({
@@ -56720,6 +59133,106 @@ var ConsumablesStatusSchema = object({
56720
59133
  items: array(ConsumableItemSchema),
56721
59134
  lastChangedAt: number()
56722
59135
  });
59136
+ /** Synthesize seed for a link-built status (no native provider).
59137
+ *
59138
+ * ⚠ NO LIVE CALLER since 2026-08-08 (device-links deleted; see
59139
+ * `CapabilityStatusSchema.empty`). The wiring guidance below was written for
59140
+ * exactly the case the operator is asking about again — a Dreame's HA
59141
+ * consumable-life sensors — so it is kept for that conversation, not because
59142
+ * anything reads it today. */
59143
+ var EMPTY_STATUS = {
59144
+ items: [],
59145
+ lastChangedAt: 0
59146
+ };
59147
+ /** Seed for a NEW link-built consumable item. `key`/`label` are overwritten
59148
+ * with the link's `itemKey` (see `status.itemArray`), so the placeholder
59149
+ * empty strings never survive into a validated item. Link-built items are
59150
+ * not resettable — there is no native provider to receive `reset()`.
59151
+ *
59152
+ * Wiring guidance (HA vacuum consumable-life sensors):
59153
+ * - a percent-remaining source (`numeric-sensor`, unit '%') → `level` via
59154
+ * `identity` (or `linear` scale 1 offset 0 clamp [0,100] to be safe);
59155
+ * - an hours-remaining source (e.g. Dreame 'Main Brush Time Left', unit 'h')
59156
+ * → `level` via `linear` with scale = 100 / max-hours for that item
59157
+ * (e.g. main brush 300 h → scale 0.3333) + clamp [0,100];
59158
+ * - a discrete source (`enum-sensor`, e.g. mop pad 'installed') → `status`
59159
+ * via `enum-map` (e.g. { installed: 'ok', missing: 'replace' }).
59160
+ * A numeric→'replace' THRESHOLD (level < 10 → 'replace') is NOT expressible
59161
+ * with the current transform kinds — leave `status` null (valid) until the
59162
+ * expression transform lands. */
59163
+ /** Generic Customize target for one consumable item (D936). Native rows stay read-only. */
59164
+ var consumablesCustomize = {
59165
+ version: 1,
59166
+ targets: [{
59167
+ id: "items",
59168
+ cardinality: "keyedArray",
59169
+ vocabulary: { cap: "consumables" },
59170
+ deviceTypes: Object.values(DeviceType),
59171
+ apply: "add",
59172
+ path: "items",
59173
+ keyField: "key",
59174
+ labelField: "label",
59175
+ itemSchema: ConsumableItemSchema,
59176
+ nativeItems: "read-only",
59177
+ sourceReport: { status: "assignment-status" },
59178
+ fields: [
59179
+ {
59180
+ path: "level",
59181
+ sources: [{
59182
+ kind: "numeric",
59183
+ transforms: [{ kind: "identity" }, {
59184
+ kind: "linear",
59185
+ defaultScale: 1,
59186
+ defaultOffset: 0,
59187
+ clampMin: 0,
59188
+ clampMax: 100
59189
+ }]
59190
+ }]
59191
+ },
59192
+ {
59193
+ path: "remaining.value",
59194
+ sources: [{
59195
+ kind: "numeric",
59196
+ transforms: [{ kind: "identity" }]
59197
+ }],
59198
+ literals: [{
59199
+ path: "remaining.unit",
59200
+ values: [...ConsumableRemainingUnitSchema.options]
59201
+ }]
59202
+ },
59203
+ {
59204
+ path: "status",
59205
+ sources: [{
59206
+ kind: "enum",
59207
+ transforms: [{
59208
+ kind: "enum-map",
59209
+ outputValues: [...ConsumableStatusSchema.options],
59210
+ unmapped: null
59211
+ }]
59212
+ }]
59213
+ }
59214
+ ],
59215
+ traits: [{
59216
+ path: "kind",
59217
+ values: [...ConsumableKindSchema.options],
59218
+ defaultValue: "wear"
59219
+ }, {
59220
+ path: "form",
59221
+ values: [...ConsumableFormSchema.options],
59222
+ defaultValue: "part"
59223
+ }],
59224
+ companions: [{
59225
+ kind: "clock",
59226
+ path: "lastChangedAt",
59227
+ when: "add"
59228
+ }, {
59229
+ kind: "clock",
59230
+ path: "lastFetchedAt",
59231
+ when: "add"
59232
+ }],
59233
+ advancedExpression: true
59234
+ }]
59235
+ };
56723
59236
  var consumablesCapability = {
56724
59237
  name: "consumables",
56725
59238
  scope: "device",
@@ -56757,10 +59270,7 @@ reset: method(object({
56757
59270
  status: {
56758
59271
  schema: ConsumablesStatusSchema,
56759
59272
  kind: "push",
56760
- empty: {
56761
- items: [],
56762
- lastChangedAt: 0
56763
- },
59273
+ empty: EMPTY_STATUS,
56764
59274
  itemArray: {
56765
59275
  path: "items",
56766
59276
  keyField: "key",
@@ -56796,6 +59306,7 @@ reset: method(object({
56796
59306
  * brush's remaining life and a dishwasher's salt are each recorded the moment
56797
59307
  * their provider reports them; an item that appears later gets its series.
56798
59308
  */
59309
+ customize: consumablesCustomize,
56799
59310
  history: {
56800
59311
  fields: {},
56801
59312
  items: {
@@ -57175,6 +59686,30 @@ var dayNightCapability = {
57175
59686
  volatileStateFields: ["lastFetchedAt"]
57176
59687
  };
57177
59688
  /**
59689
+ * display-palette — the cluster's one colour table (D939).
59690
+ *
59691
+ * Hub singleton. `getPalette` reports `unknown` when the settings store
59692
+ * cannot be read; it does not pretend the bundled preset was stored.
59693
+ * `setPalette` refuses a palette that fails the ΔE / contrast rule and names
59694
+ * the pairs.
59695
+ */
59696
+ var presetSummarySchema = object({
59697
+ id: string(),
59698
+ name: string(),
59699
+ swatches: record(string(), paletteSwatchSchema),
59700
+ fallbacks: array(string())
59701
+ });
59702
+ method(_void(), paletteResultSchema, {
59703
+ auth: "protected",
59704
+ role: "viewer"
59705
+ }), method(_void(), array(presetSummarySchema).readonly(), {
59706
+ auth: "protected",
59707
+ role: "viewer"
59708
+ }), method(setPaletteInputSchema, paletteReadySchema, {
59709
+ kind: "mutation",
59710
+ auth: "admin"
59711
+ });
59712
+ /**
57178
59713
  * Generic device-level status snapshot. Auto-registered by `BaseDevice`
57179
59714
  * for every device, regardless of provider — the kernel needs a uniform
57180
59715
  * cap-keyed slice for the basic device flags every consumer expects to
@@ -57538,6 +60073,36 @@ var dishwasherCapability = {
57538
60073
  powerOn: { kind: "boolean" }
57539
60074
  } }
57540
60075
  };
60076
+ /** Pulse override: a rising edge advances `lastPressedAt` and the press count. */
60077
+ var doorbellCustomize = {
60078
+ version: 1,
60079
+ targets: [{
60080
+ id: "pressed",
60081
+ cardinality: "event",
60082
+ shape: "pulse",
60083
+ vocabulary: {
60084
+ cap: "doorbell",
60085
+ eventName: "onPressed"
60086
+ },
60087
+ deviceTypes: [DeviceType.Camera],
60088
+ apply: "add",
60089
+ applyAuthority: { kind: "composition-claim" },
60090
+ eventName: "onPressed",
60091
+ edges: ["rising"],
60092
+ timestampPath: "lastPressedAt",
60093
+ counterPath: "pressCountSinceStart",
60094
+ highWater: "composer-advance",
60095
+ combine: "any",
60096
+ debounce: {
60097
+ kind: "rising-edge",
60098
+ defaultDebounceMs: 2e3,
60099
+ changedAtRequired: true
60100
+ },
60101
+ sources: [{ kind: "binary" }, { kind: "switch" }],
60102
+ sourceReport: { status: "assignment-status" },
60103
+ advancedExpression: true
60104
+ }]
60105
+ };
57541
60106
  var DoorbellStatusSchema = object({
57542
60107
  /** Ms epoch of the last press. null = never observed since this provider started. */
57543
60108
  lastPressedAt: number().nullable(),
@@ -57604,7 +60169,8 @@ onPressed: {
57604
60169
  /**
57605
60170
  * History (D850): none — `pressCountSinceStart` resets with the addon, so it is not a monotonic meter; presses live in the events ledger.
57606
60171
  */
57607
- history: "none"
60172
+ history: "none",
60173
+ customize: doorbellCustomize
57608
60174
  };
57609
60175
  /**
57610
60176
  * Enum-state sensor — a string value picked from a finite option set.
@@ -58476,7 +61042,10 @@ var humidifierCapability = {
58476
61042
  */
58477
61043
  var HumiditySensorStatusSchema = object({
58478
61044
  /** Current relative humidity, 0..100. */
58479
- percent: number().min(0).max(100),
61045
+ percent: number().min(0).max(100).meta({
61046
+ unit: "%",
61047
+ label: "Humidity"
61048
+ }),
58480
61049
  /** Ms epoch when the slice was last updated. */
58481
61050
  lastFetchedAt: number(),
58482
61051
  /** Live display unit from the upstream source (e.g. HA
@@ -58518,7 +61087,12 @@ var humiditySensorCapability = {
58518
61087
  } } },
58519
61088
  /** Clock fields: written, but excluded from the compare that decides
58520
61089
  * whether persisting is worth a SQLite commit. */
58521
- volatileStateFields: ["lastFetchedAt"]
61090
+ volatileStateFields: ["lastFetchedAt"],
61091
+ customize: {
61092
+ version: 1,
61093
+ advanced: "derive",
61094
+ targets: []
61095
+ }
58522
61096
  };
58523
61097
  /**
58524
61098
  * Image display cap. Models a single still image exposed by an integration —
@@ -60000,6 +62574,38 @@ authKey: string().optional() }), object({
60000
62574
  /** Human-readable error when `ok: false`. */
60001
62575
  error: string().optional()
60002
62576
  }), { kind: "mutation" });
62577
+ /** Span override: start on a rising edge, end on a fall or this timeout. */
62578
+ var motionCustomize = {
62579
+ version: 1,
62580
+ targets: [{
62581
+ id: "detected",
62582
+ cardinality: "event",
62583
+ shape: "span",
62584
+ vocabulary: {
62585
+ cap: "motion",
62586
+ eventName: "onMotionChanged"
62587
+ },
62588
+ deviceTypes: [DeviceType.Camera],
62589
+ apply: "replace",
62590
+ applyAuthority: {
62591
+ kind: "camera-sensors",
62592
+ timeoutField: "motionCooldownMs"
62593
+ },
62594
+ eventName: "onMotionChanged",
62595
+ start: "rising-edge",
62596
+ end: "falling-edge-or-timeout",
62597
+ timeoutMs: 3e4,
62598
+ combine: "any",
62599
+ sourceModes: [
62600
+ "in-addition",
62601
+ "confirm",
62602
+ "replace"
62603
+ ],
62604
+ sources: [{ kind: "binary" }, { kind: "switch" }],
62605
+ sourceReport: { status: "assignment-status" },
62606
+ advancedExpression: false
62607
+ }]
62608
+ };
60003
62609
  var MotionStatusSchema = object({
60004
62610
  detected: boolean(),
60005
62611
  /** Ms epoch of the last detected-true observation. Null if never detected. */
@@ -60139,7 +62745,8 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
60139
62745
  history: { fields: { detected: {
60140
62746
  kind: "boolean",
60141
62747
  excludeDeviceTypes: [DeviceType.Camera]
60142
- } } }
62748
+ } } },
62749
+ customize: motionCustomize
60143
62750
  };
60144
62751
  /**
60145
62752
  * Motion-trigger toggle for accessory devices.
@@ -61958,6 +64565,30 @@ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly(
61958
64565
  kind: "mutation",
61959
64566
  auth: "admin"
61960
64567
  });
64568
+ var CORE_ULTRA_265K_IGPU_CLOCK_MHZ = 2e3;
64569
+ var positiveOrNull = number().nullable().transform((value) => value !== null && Number.isFinite(value) && value > 0 ? value : null);
64570
+ var textOrNull = string().nullable().transform((value) => value !== null && value.trim() !== "" ? value : null);
64571
+ var PrecisionGopsSchema = object({
64572
+ int8: positiveOrNull,
64573
+ fp16: positiveOrNull
64574
+ });
64575
+ /** What one accelerator device reported. Every failed query is null. */
64576
+ var AcceleratorComputeSchema = object({
64577
+ deviceKey: string(),
64578
+ fullDeviceName: textOrNull,
64579
+ executionUnits: positiveOrNull,
64580
+ clockMHz: positiveOrNull,
64581
+ gops: PrecisionGopsSchema.nullable(),
64582
+ architecture: textOrNull,
64583
+ npuName: textOrNull,
64584
+ tops: positiveOrNull,
64585
+ vendor: textOrNull,
64586
+ webgpuArchitecture: textOrNull,
64587
+ webgpuDevice: textOrNull,
64588
+ computeUnits: positiveOrNull
64589
+ });
64590
+ object({ accelerators: array(AcceleratorComputeSchema).nullable() });
64591
+ 64 * CORE_ULTRA_265K_IGPU_CLOCK_MHZ;
61961
64592
  var ModelFormatSchema = _enum(MODEL_FORMATS);
61962
64593
  var HwAccelBackendInputSchema = _enum([
61963
64594
  "videotoolbox",
@@ -62071,7 +64702,12 @@ var HardwareInfoSchema = object({
62071
64702
  availableRAM_MB: number(),
62072
64703
  gpu: GpuInfoSchema.nullable(),
62073
64704
  npu: NpuInfoSchema.nullable(),
62074
- coral: CoralInfoSchema.nullable().optional()
64705
+ coral: CoralInfoSchema.nullable().optional(),
64706
+ /**
64707
+ * Per-accelerator compute (D930). Omitted by a node that has not probed it.
64708
+ * `null` fields inside an entry are a failed query, never a zero.
64709
+ */
64710
+ accelerators: array(AcceleratorComputeSchema).readonly().optional()
62075
64711
  });
62076
64712
  var PlatformScoreSchema = object({
62077
64713
  runtime: literal("python"),
@@ -62155,9 +64791,15 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
62155
64791
  */
62156
64792
  var PowerMeterStatusSchema = object({
62157
64793
  /** Instantaneous power draw in watts. */
62158
- watts: number().optional(),
64794
+ watts: number().optional().meta({
64795
+ unit: "W",
64796
+ label: "Power"
64797
+ }),
62159
64798
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
62160
- kwhTotal: number().optional(),
64799
+ kwhTotal: number().optional().meta({
64800
+ unit: "kWh",
64801
+ label: "Energy"
64802
+ }),
62161
64803
  /** Voltage in volts. */
62162
64804
  volts: number().optional(),
62163
64805
  /** Current in amperes. */
@@ -62242,7 +64884,12 @@ var powerMeterCapability = {
62242
64884
  } },
62243
64885
  /** Clock fields: written, but excluded from the compare that decides
62244
64886
  * whether persisting is worth a SQLite commit. */
62245
- volatileStateFields: ["lastFetchedAt"]
64887
+ volatileStateFields: ["lastFetchedAt"],
64888
+ customize: {
64889
+ version: 1,
64890
+ advanced: "derive",
64891
+ targets: []
64892
+ }
62246
64893
  };
62247
64894
  /**
62248
64895
  * Presence cap. Models HA `person.*` and `device_tracker.*` entities
@@ -62687,9 +65334,9 @@ var PtzOptionsSchema = object({
62687
65334
  * Reolink preset 0, Hikvision preset '1', Dahua preset 1 -- and on this fleet
62688
65335
  * not one of the three cameras honours its own:
62689
65336
  *
62690
- * 592 Videocamera camera Daniel (reolink) preset 0 holds "stanza"
62691
- * 1438 Videocamera dispensa (hikvision) preset 1 holds "Credenza"
62692
- * 3836 Videocamera studio (amcrest) preset 1 holds "Preset1"
65337
+ * 107 Camera camera Carol (reolink) preset 0 holds "stanza"
65338
+ * 1438 Camera dispensa (hikvision) preset 1 holds "Credenza"
65339
+ * 3836 Camera studio (amcrest) preset 1 holds "Preset1"
62693
65340
  *
62694
65341
  * So `goHome` meant "go wherever the operator happened to save in slot 0 or 1",
62695
65342
  * and two of the three swallowed the failure in a bare `catch`. For autotrack
@@ -63014,6 +65661,126 @@ var ptzAutotrackCapability = {
63014
65661
  */
63015
65662
  history: "none"
63016
65663
  };
65664
+ var RUNNING_POWER_START_DELAY_MS = 3e4;
65665
+ var RUNNING_POWER_STOP_DELAY_MS = 18e4;
65666
+ var RunningStateSourceSchema = _enum(["native", "assigned"]);
65667
+ var RunningStateStatusSchema = object({
65668
+ /** null = unknown — never coerced to false (D393). */
65669
+ running: boolean().nullable(),
65670
+ /** Epoch ms the current boolean began; null while `running` is null. */
65671
+ since: number().nullable(),
65672
+ source: RunningStateSourceSchema.meta({ label: "Source" }),
65673
+ phase: string().nullable(),
65674
+ /** null until a reading has been published (D393). */
65675
+ lastFetchedAt: number().nullable()
65676
+ });
65677
+ var RunningFlipEventDataSchema = object({
65678
+ deviceId: number(),
65679
+ since: number().nullable(),
65680
+ phase: string().nullable()
65681
+ });
65682
+ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
65683
+ /** Generic Customize target for the running boolean (D936). */
65684
+ var runningCustomize = {
65685
+ version: 1,
65686
+ advanced: "derive",
65687
+ targets: [{
65688
+ id: "running",
65689
+ cardinality: "scalar",
65690
+ vocabulary: {
65691
+ cap: "running-state",
65692
+ stateField: "running"
65693
+ },
65694
+ deviceTypes: [
65695
+ DeviceType.Dishwasher,
65696
+ DeviceType.Vacuum,
65697
+ DeviceType.LawnMower,
65698
+ DeviceType.MediaPlayer,
65699
+ DeviceType.WaterHeater,
65700
+ DeviceType.Humidifier,
65701
+ DeviceType.Fan,
65702
+ DeviceType.Climate,
65703
+ DeviceType.Thermostat,
65704
+ DeviceType.PetFeeder
65705
+ ],
65706
+ apply: "add-or-replace",
65707
+ path: "running",
65708
+ sources: [
65709
+ {
65710
+ kind: "switch",
65711
+ transforms: [{ kind: "identity" }]
65712
+ },
65713
+ {
65714
+ kind: "binary",
65715
+ transforms: [{ kind: "identity" }, { kind: "invert" }]
65716
+ },
65717
+ {
65718
+ kind: "numeric",
65719
+ requiredUnit: "W",
65720
+ transforms: [{
65721
+ kind: "threshold",
65722
+ comparison: "gte",
65723
+ defaultThreshold: 5,
65724
+ defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
65725
+ defaultStopDwellMs: RUNNING_POWER_STOP_DELAY_MS,
65726
+ thresholdUnit: "W"
65727
+ }]
65728
+ }
65729
+ ],
65730
+ companions: [
65731
+ {
65732
+ kind: "constant",
65733
+ path: "source",
65734
+ value: "assigned",
65735
+ when: "always"
65736
+ },
65737
+ {
65738
+ kind: "constant",
65739
+ path: "phase",
65740
+ value: null,
65741
+ when: "always"
65742
+ },
65743
+ {
65744
+ kind: "clock",
65745
+ path: "lastFetchedAt",
65746
+ when: "always"
65747
+ },
65748
+ {
65749
+ kind: "transition-time",
65750
+ path: "since",
65751
+ sourceChangedAt: "prefer"
65752
+ }
65753
+ ],
65754
+ sourceReport: {
65755
+ status: "assignment-status",
65756
+ runtimeField: "source",
65757
+ nativeValue: "native",
65758
+ assignedValue: "assigned"
65759
+ },
65760
+ advancedExpression: true
65761
+ }]
65762
+ };
65763
+ var runningStateCapability = {
65764
+ name: "running-state",
65765
+ scope: "device",
65766
+ deviceNative: true,
65767
+ mode: "singleton",
65768
+ deviceTypes: RUNNING_DEVICE_TYPES,
65769
+ methods: {},
65770
+ events: {
65771
+ onStarted: { data: RunningFlipEventDataSchema },
65772
+ onFinished: { data: RunningFlipEventDataSchema }
65773
+ },
65774
+ status: {
65775
+ schema: RunningStateStatusSchema,
65776
+ kind: "push"
65777
+ },
65778
+ runtimeState: RunningStateStatusSchema,
65779
+ durability: "restored",
65780
+ history: { fields: { running: { kind: "boolean" } } },
65781
+ volatileStateFields: ["lastFetchedAt"],
65782
+ customize: runningCustomize
65783
+ };
63017
65784
  /**
63018
65785
  * reboot — device-scoped capability for "soft" device reboots (firmware
63019
65786
  * reboot via vendor protocol; cameras, NVRs, doorbells). Surfaces a
@@ -63080,7 +65847,7 @@ var RecordingAvailabilitySchema = object({
63080
65847
  * would look identical. But the answer used to say nothing about that, so a
63081
65848
  * caller asking "what can I export?" read the single preferred profile as
63082
65849
  * the only one that exists — on this deployment every camera records `high`
63083
- * AND `low`, the low tree holding 14 GB for camera 615 alone, and the export
65850
+ * AND `low`, the low tree holding 14 GB for camera 101 alone, and the export
63084
65851
  * UI could not see it.
63085
65852
  *
63086
65853
  * Cheap: it is the same shallow directory read the profile CHOICE already
@@ -63179,7 +65946,7 @@ var RecordingSourceOptionsSchema = object({
63179
65946
  * `sparse` = gaps are the absence of one, and must be drawn as such.
63180
65947
  *
63181
65948
  * Not an onboard-only concession: measured 2026-09-24, OUR bar covers 98.8 %
63182
- * of 592's day and 1.2 % of 1436's. It is a fact about a (source, camera)
65949
+ * of 107's day and 1.2 % of 1436's. It is a fact about a (source, camera)
63183
65950
  * pair, and ours answers it per camera from `deriveRecordingMode`. */
63184
65951
  coverage: _enum(["continuous", "sparse"]),
63185
65952
  /** Where the playhead may be put.
@@ -63255,7 +66022,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(RecordingSourceS
63255
66022
  * merely discouraged (D554 amended).
63256
66023
  *
63257
66024
  * It was learned the expensive way on `videoclips.listClips`: measured
63258
- * on the live hub 2026-09-20, device 592 bound to `recorder` AND
66025
+ * on the live hub 2026-09-20, device 107 bound to `recorder` AND
63259
66026
  * `provider-reolink`, a bare call with `limit: 3` answered SIX rows,
63260
66027
  * three from each source, merged — `device-collection-dispatch.ts`
63261
66028
  * leaves an unpinned fan-out un-narrowed, so absence buys the union the
@@ -63856,7 +66623,7 @@ var ExportSpeedSchema = number().min(.25).max(32);
63856
66623
  * on a 10 h window holding 29,393 s of footage every range landed late by the
63857
66624
  * gap accumulated before it — up to 6,607 s, well past EOF. Nothing matched,
63858
66625
  * the video was a uniform timelapse, and the log line reported the five ranges
63859
- * that had been ASKED for (2026-08-13, export `57d14363`, camera 615).
66626
+ * that had been ASKED for (2026-08-13, export `57d14363`, camera 101).
63860
66627
  *
63861
66628
  * Relative and not absolute epoch, because an absolute epoch would make every
63862
66629
  * call site responsible for the same subtraction.
@@ -64736,7 +67503,7 @@ getStatus: method(object({ deviceId: number() }), RecordingSignalStatusSchema) }
64736
67503
  * which put a "Scenes" tab on one camera's detail page. That is the wrong shape
64737
67504
  * for the thing: a scene is a standing question about the property ("is the bin
64738
67505
  * still out"), and the operator's question is "which of my scenes have tripped",
64739
- * across every camera at once — not "what does camera 617 think". Buried one
67506
+ * across every camera at once — not "what does camera 102 think". Buried one
64740
67507
  * camera deep it also could not be found. The surface is now a top-level admin
64741
67508
  * page (`/scenes`, `pages/Scenes.tsx`) that lists every scene on every camera and
64742
67509
  * picks the camera inside the create flow, the same shape Events and Faces have.
@@ -65185,7 +67952,20 @@ var ZoneRuleSchema = object({
65185
67952
  * Defaults to `true` so operators creating a rule via the UI
65186
67953
  * see it active immediately.
65187
67954
  */
65188
- enabled: boolean().default(true)
67955
+ enabled: boolean().default(true),
67956
+ /**
67957
+ * Package stage only. When true, a package candidate may open from a
67958
+ * scene difference in this rule's zone after a person leaves. The
67959
+ * package model, when it boxes something overlapping, is extra evidence
67960
+ * and is not the gate. Absent or false keeps today's model path.
67961
+ */
67962
+ detectBySceneDifference: boolean().optional(),
67963
+ /**
67964
+ * Package stage only. When true, a promoted package is shown to the
67965
+ * `llm` cap before the delivery event is emitted. Absent or false emits
67966
+ * as today. Usable with or without `detectBySceneDifference`.
67967
+ */
67968
+ confirmWithLlm: boolean().optional()
65189
67969
  });
65190
67970
  array(ZoneRuleSchema).readonly();
65191
67971
  /**
@@ -65780,7 +68560,7 @@ function buildStreamParamsConfigSchema(options, status) {
65780
68560
  * `getSettingsUISchema()` surface.
65781
68561
  */
65782
68562
  var SwitchStatusSchema = object({
65783
- on: boolean(),
68563
+ on: boolean().meta({ label: "On" }),
65784
68564
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
65785
68565
  lastChangedAt: number()
65786
68566
  });
@@ -65839,7 +68619,12 @@ var switchCapability = {
65839
68619
  label: "On",
65840
68620
  kind: "boolean"
65841
68621
  }
65842
- }] }
68622
+ }] },
68623
+ customize: {
68624
+ version: 1,
68625
+ advanced: "derive",
68626
+ targets: []
68627
+ }
65843
68628
  };
65844
68629
  /** C0 controls, DEL and the C1 range: none of them belongs in a name. */
65845
68630
  function hasControlCharacter(value) {
@@ -66435,7 +69220,10 @@ var tamperCapability = {
66435
69220
  */
66436
69221
  var TemperatureSensorStatusSchema = object({
66437
69222
  /** Current temperature in Celsius. */
66438
- celsius: number(),
69223
+ celsius: number().meta({
69224
+ unit: "°C",
69225
+ label: "Temperature"
69226
+ }),
66439
69227
  /** Ms epoch when the slice was last updated (push or poll). */
66440
69228
  lastFetchedAt: number(),
66441
69229
  /** Live display unit from the upstream source (e.g. HA
@@ -66478,7 +69266,12 @@ var temperatureSensorCapability = {
66478
69266
  } } },
66479
69267
  /** Clock fields: written, but excluded from the compare that decides
66480
69268
  * whether persisting is worth a SQLite commit. */
66481
- volatileStateFields: ["lastFetchedAt"]
69269
+ volatileStateFields: ["lastFetchedAt"],
69270
+ customize: {
69271
+ version: 1,
69272
+ advanced: "derive",
69273
+ targets: []
69274
+ }
66482
69275
  };
66483
69276
  /**
66484
69277
  * toast — system-scoped singleton capability that streams toast
@@ -67741,7 +70534,7 @@ method(object({}), array(TrainingProviderDescriptorSchema).readonly(), { auth: "
67741
70534
  * - **Jobs.** A persisted state machine, a reconcile loop against the
67742
70535
  * provider, a cost guard, a daily orphan sweep and the retention rules.
67743
70536
  * - **The return flow.** Verified artefacts → Model Studio
67744
- * (`custom-model-registry.importModelBundle`) → canary on cameras →
70537
+ * (`custom-model-registry.importModelBundle`) → canary on accelerators →
67745
70538
  * rollback. Nothing is ever registered automatically.
67746
70539
  *
67747
70540
  * Plan/start takes a live {@link TrainingCorpusSelection} (collections +
@@ -67878,20 +70671,24 @@ var TrainingProgressPointSchema = object({
67878
70671
  map50: number().nullable(),
67879
70672
  map50_95: number().nullable()
67880
70673
  });
70674
+ /** One accelerator: a `(node, inference device)` that runs the root detector. */
70675
+ var TrainingAcceleratorRefSchema = object({
70676
+ nodeId: string(),
70677
+ deviceKey: string()
70678
+ });
70679
+ /**
70680
+ * A canary pins the registered model on chosen ACCELERATORS — a model is
70681
+ * chosen by the accelerator that runs it (D927); every camera balanced onto
70682
+ * one runs it. `previous` is the root-detector pin each one had (`null` = it
70683
+ * ran its default), exactly, so rollback restores it.
70684
+ */
67881
70685
  var TrainingCanarySchema = object({
67882
- deviceIds: array(number().int()).readonly(),
70686
+ accelerators: array(TrainingAcceleratorRefSchema).readonly(),
67883
70687
  since: number(),
67884
- /** Every override the canary replaced, exactly, so rollback restores it. */
67885
- previous: array(object({
67886
- deviceId: number().int(),
67887
- nodeId: string(),
67888
- deviceKey: string(),
67889
- patch: object({
67890
- modelId: string().optional(),
67891
- settings: record(string(), unknown()).readonly().optional()
67892
- }).nullable()
67893
- })).readonly()
70688
+ previous: array(TrainingAcceleratorRefSchema.extend({ modelId: string().nullable() })).readonly()
67894
70689
  });
70690
+ /** An accelerator a canary may pin: it runs the root detector, on this model now. */
70691
+ var TrainingCanaryTargetSchema = TrainingAcceleratorRefSchema.extend({ pinnedModelId: string().nullable() });
67895
70692
  var TrainingJobSchema = object({
67896
70693
  id: string(),
67897
70694
  idempotencyKey: string(),
@@ -68003,11 +70800,11 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
68003
70800
  kind: "mutation",
68004
70801
  auth: "admin",
68005
70802
  timeoutMs: 12e4
68006
- }), method(IdInput, TrainingResultSchema.nullable(), { auth: "admin" }), method(IdInput.extend({ canaryDeviceIds: array(number().int()).readonly() }), TrainingJobSchema, {
70803
+ }), method(IdInput, TrainingResultSchema.nullable(), { auth: "admin" }), method(_void(), array(TrainingCanaryTargetSchema).readonly(), { auth: "admin" }), method(IdInput.extend({ canaryAccelerators: array(TrainingAcceleratorRefSchema).readonly() }), TrainingJobSchema, {
68007
70804
  kind: "mutation",
68008
70805
  auth: "admin",
68009
70806
  timeoutMs: 30 * 6e4
68010
- }), method(IdInput.extend({ deviceIds: array(number().int()).min(1).readonly() }), TrainingJobSchema, {
70807
+ }), method(IdInput.extend({ accelerators: array(TrainingAcceleratorRefSchema).min(1).readonly() }), TrainingJobSchema, {
68011
70808
  kind: "mutation",
68012
70809
  auth: "admin",
68013
70810
  timeoutMs: 12e4
@@ -68153,6 +70950,10 @@ function withClipEventLabels(provider, deps) {
68153
70950
  };
68154
70951
  }
68155
70952
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
70953
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Camera, DeviceType.Camera, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
70954
+ String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
70955
+ DeviceRole.BinarySensor, DeviceRole.MotionSensor;
70956
+ new Set(CAP_NAMES);
68156
70957
  Object.freeze({
68157
70958
  person: .5,
68158
70959
  vehicle: .5,
@@ -68518,6 +71319,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
68518
71319
  ptzAutotrack: ptzAutotrackCapability,
68519
71320
  recordingOnboard: recordingOnboardCapability,
68520
71321
  recordingSignal: recordingSignalCapability,
71322
+ runningState: runningStateCapability,
68521
71323
  sceneMonitor: sceneMonitorCapability,
68522
71324
  scriptRunner: scriptRunnerCapability,
68523
71325
  smoke: smokeCapability,
@@ -69400,7 +72202,7 @@ var BaseDeviceProvider = class extends BaseAddon {
69400
72202
  * A top-level persisted row with NO configuration is a leftover, not a
69401
72203
  * device — quarantine it instead of dialling it.
69402
72204
  *
69403
- * Device 614 was deleted, resurrected as a config-less shell by a write
72205
+ * Device 105 was deleted, resurrected as a config-less shell by a write
69404
72206
  * already in flight (D376), and then dialled at every single boot: eight
69405
72207
  * `Failed to restore device — bounded retry scheduled` lines in one day,
69406
72208
  * each one the same Zod refusal on `host` and `password`. The bound was
@@ -72710,6 +75512,27 @@ Object.freeze({
72710
75512
  access: "create",
72711
75513
  role: "viewer"
72712
75514
  },
75515
+ "displayPalette.getPalette": {
75516
+ capName: "display-palette",
75517
+ capScope: "system",
75518
+ addonId: null,
75519
+ access: "view",
75520
+ role: "viewer"
75521
+ },
75522
+ "displayPalette.listPresets": {
75523
+ capName: "display-palette",
75524
+ capScope: "system",
75525
+ addonId: null,
75526
+ access: "view",
75527
+ role: "viewer"
75528
+ },
75529
+ "displayPalette.setPalette": {
75530
+ capName: "display-palette",
75531
+ capScope: "system",
75532
+ addonId: null,
75533
+ access: "create",
75534
+ role: "admin"
75535
+ },
72713
75536
  "doorbell.getStatus": {
72714
75537
  capName: "doorbell",
72715
75538
  capScope: "device",
@@ -75629,20 +78452,6 @@ Object.freeze({
75629
78452
  access: "create",
75630
78453
  role: "admin"
75631
78454
  },
75632
- "pipelineExecutor.clearDeviceOverrides": {
75633
- capName: "pipeline-executor",
75634
- capScope: "system",
75635
- addonId: null,
75636
- access: "delete",
75637
- role: "admin"
75638
- },
75639
- "pipelineExecutor.clearModelBoundDeviceOverrides": {
75640
- capName: "pipeline-executor",
75641
- capScope: "system",
75642
- addonId: null,
75643
- access: "delete",
75644
- role: "admin"
75645
- },
75646
78455
  "pipelineExecutor.deleteModel": {
75647
78456
  capName: "pipeline-executor",
75648
78457
  capScope: "system",
@@ -75685,13 +78494,6 @@ Object.freeze({
75685
78494
  access: "view",
75686
78495
  role: "admin"
75687
78496
  },
75688
- "pipelineExecutor.getDefaultSteps": {
75689
- capName: "pipeline-executor",
75690
- capScope: "system",
75691
- addonId: null,
75692
- access: "view",
75693
- role: "admin"
75694
- },
75695
78497
  "pipelineExecutor.getDetectionConfigSchema": {
75696
78498
  capName: "pipeline-executor",
75697
78499
  capScope: "system",
@@ -75713,20 +78515,6 @@ Object.freeze({
75713
78515
  access: "view",
75714
78516
  role: "admin"
75715
78517
  },
75716
- "pipelineExecutor.getGlobalPipelineConfig": {
75717
- capName: "pipeline-executor",
75718
- capScope: "system",
75719
- addonId: null,
75720
- access: "view",
75721
- role: "admin"
75722
- },
75723
- "pipelineExecutor.getGlobalSteps": {
75724
- capName: "pipeline-executor",
75725
- capScope: "system",
75726
- addonId: null,
75727
- access: "view",
75728
- role: "admin"
75729
- },
75730
78518
  "pipelineExecutor.getInferenceDeviceHealth": {
75731
78519
  capName: "pipeline-executor",
75732
78520
  capScope: "system",
@@ -75986,13 +78774,6 @@ Object.freeze({
75986
78774
  access: "view",
75987
78775
  role: "admin"
75988
78776
  },
75989
- "pipelineOrchestrator.getCameraStepOverrides": {
75990
- capName: "pipeline-orchestrator",
75991
- capScope: "system",
75992
- addonId: null,
75993
- access: "view",
75994
- role: "admin"
75995
- },
75996
78777
  "pipelineOrchestrator.getCameraSwitches": {
75997
78778
  capName: "pipeline-orchestrator",
75998
78779
  capScope: "system",
@@ -76231,13 +79012,6 @@ Object.freeze({
76231
79012
  access: "create",
76232
79013
  role: "admin"
76233
79014
  },
76234
- "pipelineOrchestrator.setCameraPipelineForAgent": {
76235
- capName: "pipeline-orchestrator",
76236
- capScope: "system",
76237
- addonId: null,
76238
- access: "create",
76239
- role: "admin"
76240
- },
76241
79015
  "pipelineOrchestrator.setCameraSensors": {
76242
79016
  capName: "pipeline-orchestrator",
76243
79017
  capScope: "system",
@@ -76245,42 +79019,42 @@ Object.freeze({
76245
79019
  access: "create",
76246
79020
  role: "admin"
76247
79021
  },
76248
- "pipelineOrchestrator.setCameraStepOverride": {
79022
+ "pipelineOrchestrator.setCameraStepSettings": {
76249
79023
  capName: "pipeline-orchestrator",
76250
79024
  capScope: "system",
76251
79025
  addonId: null,
76252
79026
  access: "create",
76253
79027
  role: "admin"
76254
79028
  },
76255
- "pipelineOrchestrator.setCameraStepSettings": {
79029
+ "pipelineOrchestrator.setCameraStepToggle": {
76256
79030
  capName: "pipeline-orchestrator",
76257
79031
  capScope: "system",
76258
79032
  addonId: null,
76259
79033
  access: "create",
76260
79034
  role: "admin"
76261
79035
  },
76262
- "pipelineOrchestrator.setCameraStepToggle": {
79036
+ "pipelineOrchestrator.setCameraSwitch": {
76263
79037
  capName: "pipeline-orchestrator",
76264
79038
  capScope: "system",
76265
79039
  addonId: null,
76266
79040
  access: "create",
76267
79041
  role: "admin"
76268
79042
  },
76269
- "pipelineOrchestrator.setCameraSwitch": {
79043
+ "pipelineOrchestrator.setCapabilityBinding": {
76270
79044
  capName: "pipeline-orchestrator",
76271
79045
  capScope: "system",
76272
79046
  addonId: null,
76273
79047
  access: "create",
76274
79048
  role: "admin"
76275
79049
  },
76276
- "pipelineOrchestrator.setCapabilityBinding": {
79050
+ "pipelineOrchestrator.setLoadBalancingShares": {
76277
79051
  capName: "pipeline-orchestrator",
76278
79052
  capScope: "system",
76279
79053
  addonId: null,
76280
79054
  access: "create",
76281
79055
  role: "admin"
76282
79056
  },
76283
- "pipelineOrchestrator.setLoadBalancingShares": {
79057
+ "pipelineOrchestrator.setNodeStepSettings": {
76284
79058
  capName: "pipeline-orchestrator",
76285
79059
  capScope: "system",
76286
79060
  addonId: null,
@@ -77309,6 +80083,13 @@ Object.freeze({
77309
80083
  access: "create",
77310
80084
  role: "admin"
77311
80085
  },
80086
+ "runningState.getStatus": {
80087
+ capName: "running-state",
80088
+ capScope: "device",
80089
+ addonId: null,
80090
+ access: "view",
80091
+ role: "viewer"
80092
+ },
77312
80093
  "sceneMonitor.captureReference": {
77313
80094
  capName: "scene-monitor",
77314
80095
  capScope: "device",
@@ -78639,6 +81420,13 @@ Object.freeze({
78639
81420
  access: "view",
78640
81421
  role: "admin"
78641
81422
  },
81423
+ "training.listCanaryTargets": {
81424
+ capName: "training",
81425
+ capScope: "system",
81426
+ addonId: null,
81427
+ access: "view",
81428
+ role: "admin"
81429
+ },
78642
81430
  "training.listJobs": {
78643
81431
  capName: "training",
78644
81432
  capScope: "system",
@@ -82016,6 +84804,32 @@ var APPLIANCE_CAP_VOCABULARY = {
82016
84804
  }],
82017
84805
  events: { onSent: { notOperatorFacing: "a delivery receipt of a send this system made — not a fact about the world" } }
82018
84806
  },
84807
+ "running-state": {
84808
+ scope: "device",
84809
+ noun: t("Running", "In funzione"),
84810
+ state: [{
84811
+ kind: "boolean",
84812
+ field: "running",
84813
+ label: t("Running", "In funzione"),
84814
+ whenTrue: t("When {device} starts", "Quando {device} inizia"),
84815
+ whenFalse: t("When {device} finishes", "Quando {device} finisce"),
84816
+ icon: "play"
84817
+ }],
84818
+ events: {
84819
+ onStarted: {
84820
+ category: EventCategory.RunningStarted,
84821
+ label: t("Started running", "Ha iniziato a funzionare"),
84822
+ phrase: t("When {device} starts running", "Quando {device} inizia a funzionare"),
84823
+ icon: "play"
84824
+ },
84825
+ onFinished: {
84826
+ category: EventCategory.RunningFinished,
84827
+ label: t("Finished", "Ha finito"),
84828
+ phrase: t("When {device} finishes", "Quando {device} finisce"),
84829
+ icon: "square"
84830
+ }
84831
+ }
84832
+ },
82019
84833
  update: {
82020
84834
  scope: "device",
82021
84835
  noun: t("Firmware update", "Aggiornamento firmware"),
@@ -82636,7 +85450,7 @@ var SENSOR_CAP_VOCABULARY = {
82636
85450
  state: [{
82637
85451
  kind: "boolean",
82638
85452
  field: "on",
82639
- label: t("Active", "Attivo"),
85453
+ label: t("On", "Acceso"),
82640
85454
  whenTrue: t("When {device} turns active", "Quando {device} si attiva"),
82641
85455
  whenFalse: t("When {device} turns inactive", "Quando {device} si disattiva"),
82642
85456
  icon: "toggle-right"
@@ -83175,6 +85989,7 @@ var SYSTEM_CAP_VOCABULARY = {
83175
85989
  "device-provider": system(INTERNAL),
83176
85990
  "device-removal-hook": system(INTERNAL),
83177
85991
  "device-state": system("the runtime-state mirror every trigger already reads through"),
85992
+ "display-palette": system("the cluster display palette — one colour table for every client, not a device action"),
83178
85993
  "embedding-encoder": system(ML),
83179
85994
  "face-gallery": system("the face gallery — curated on its own page"),
83180
85995
  "failure-contribution": system(INTERNAL),
@@ -85177,11 +87992,6 @@ Object.freeze({
85177
87992
  form: "single",
85178
87993
  optional: false
85179
87994
  }],
85180
- "pipelineExecutor.clearModelBoundDeviceOverrides": [{
85181
- name: "deviceIds",
85182
- form: "array",
85183
- optional: true
85184
- }],
85185
87995
  "pipelineExecutor.runPipeline": [{
85186
87996
  name: "deviceId",
85187
87997
  form: "single",
@@ -85237,11 +88047,6 @@ Object.freeze({
85237
88047
  form: "array",
85238
88048
  optional: true
85239
88049
  }],
85240
- "pipelineOrchestrator.getCameraStepOverrides": [{
85241
- name: "deviceId",
85242
- form: "single",
85243
- optional: false
85244
- }],
85245
88050
  "pipelineOrchestrator.getCameraSwitches": [{
85246
88051
  name: "deviceId",
85247
88052
  form: "single",
@@ -85282,21 +88087,11 @@ Object.freeze({
85282
88087
  form: "single",
85283
88088
  optional: false
85284
88089
  }],
85285
- "pipelineOrchestrator.setCameraPipelineForAgent": [{
85286
- name: "deviceId",
85287
- form: "single",
85288
- optional: false
85289
- }],
85290
88090
  "pipelineOrchestrator.setCameraSensors": [{
85291
88091
  name: "deviceId",
85292
88092
  form: "single",
85293
88093
  optional: false
85294
88094
  }],
85295
- "pipelineOrchestrator.setCameraStepOverride": [{
85296
- name: "deviceId",
85297
- form: "single",
85298
- optional: false
85299
- }],
85300
88095
  "pipelineOrchestrator.setCameraStepSettings": [{
85301
88096
  name: "deviceId",
85302
88097
  form: "single",
@@ -85728,6 +88523,11 @@ Object.freeze({
85728
88523
  form: "single",
85729
88524
  optional: true
85730
88525
  }],
88526
+ "runningState.getStatus": [{
88527
+ name: "deviceId",
88528
+ form: "single",
88529
+ optional: false
88530
+ }],
85731
88531
  "sceneMonitor.captureReference": [{
85732
88532
  name: "deviceId",
85733
88533
  form: "single",
@@ -85974,11 +88774,6 @@ Object.freeze({
85974
88774
  form: "single",
85975
88775
  optional: false
85976
88776
  }],
85977
- "training.canaryResult": [{
85978
- name: "deviceIds",
85979
- form: "array",
85980
- optional: false
85981
- }],
85982
88777
  "update.getStatus": [{
85983
88778
  name: "deviceId",
85984
88779
  form: "single",
@@ -86231,6 +89026,94 @@ Object.freeze({
86231
89026
  "smtp-provider": "email"
86232
89027
  });
86233
89028
  DeviceType.Camera;
89029
+ /**
89030
+ * A saved Customize assignment (D936). The schema is the type: callers use
89031
+ * `z.infer`, they do not restate the shape.
89032
+ */
89033
+ var OverrideSourceSchema = object({
89034
+ addonId: string().min(1),
89035
+ stableId: string().min(1),
89036
+ cap: string().min(1),
89037
+ fieldPath: string().min(1)
89038
+ });
89039
+ var CustomizeTransformDraftSchema = discriminatedUnion("kind", [
89040
+ object({ kind: literal("identity") }),
89041
+ object({ kind: literal("invert") }),
89042
+ object({
89043
+ kind: literal("threshold"),
89044
+ comparison: _enum(["gte", "lte"]),
89045
+ threshold: number(),
89046
+ startDwellMs: number().nonnegative(),
89047
+ stopDwellMs: number().nonnegative()
89048
+ }),
89049
+ object({
89050
+ kind: literal("linear"),
89051
+ scale: number(),
89052
+ offset: number(),
89053
+ clampMin: number().optional(),
89054
+ clampMax: number().optional()
89055
+ }),
89056
+ object({
89057
+ kind: literal("enum-map"),
89058
+ mapping: record(string(), string().nullable())
89059
+ }),
89060
+ object({ kind: literal("number") })
89061
+ ]);
89062
+ var ScalarOverrideDraftSchema = object({
89063
+ kind: literal("scalar"),
89064
+ cap: string().min(1),
89065
+ targetId: string().min(1),
89066
+ source: OverrideSourceSchema,
89067
+ transform: CustomizeTransformDraftSchema
89068
+ });
89069
+ var KeyedArrayOverrideDraftSchema = object({
89070
+ kind: literal("keyedArray"),
89071
+ cap: string().min(1),
89072
+ targetId: string().min(1),
89073
+ key: string().min(1),
89074
+ label: string().min(1),
89075
+ fieldPath: string().min(1),
89076
+ source: OverrideSourceSchema,
89077
+ transform: CustomizeTransformDraftSchema
89078
+ });
89079
+ var PulseOverrideDraftSchema = object({
89080
+ kind: literal("pulse"),
89081
+ cap: string().min(1),
89082
+ targetId: string().min(1),
89083
+ enabled: boolean(),
89084
+ debounceMs: number().nonnegative(),
89085
+ sources: array(OverrideSourceSchema).min(1)
89086
+ });
89087
+ var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: _enum([
89088
+ "in-addition",
89089
+ "confirm",
89090
+ "replace"
89091
+ ]).optional() });
89092
+ discriminatedUnion("kind", [
89093
+ ScalarOverrideDraftSchema,
89094
+ KeyedArrayOverrideDraftSchema,
89095
+ PulseOverrideDraftSchema,
89096
+ object({
89097
+ kind: literal("span"),
89098
+ cap: string().min(1),
89099
+ targetId: string().min(1),
89100
+ timeoutMs: number().nonnegative(),
89101
+ cooldownMs: number().nonnegative().optional(),
89102
+ sources: array(SpanSourceDraftSchema)
89103
+ })
89104
+ ]);
89105
+ object({
89106
+ targetId: string().min(1),
89107
+ configured: boolean(),
89108
+ source: _enum(["native", "assigned"]),
89109
+ state: _enum([
89110
+ "active",
89111
+ "stale",
89112
+ "released",
89113
+ "unavailable"
89114
+ ]),
89115
+ reason: string().nullable()
89116
+ });
86234
89117
  var G711_SCALE_CORRECTION_DB = {
86235
89118
  PCMU: 20 * Math.log10(4),
86236
89119
  PCMA: 20 * Math.log10(8)
@@ -86283,40 +89166,7 @@ var NC_AUDIO_DEFAULTS = {
86283
89166
  samplingSeconds: 10
86284
89167
  };
86285
89168
  new Set(["devices", "classes"]);
86286
- /**
86287
- * WHICH narrowing filter speaks about WHICH system-event kind — one predicate,
86288
- * consumed by the rule ENGINE and by every rule EDITOR.
86289
- *
86290
- * ── The failure this file exists for ───────────────────────────────────────
86291
- * `NcSystemEventConditionSchema` carries four optional narrowing lists
86292
- * (`deviceIds`, `deviceTypes`, `nodeIds`, `packageNames`) beside a required
86293
- * `kinds` gate. They are not four filters over one vocabulary: each belongs to
86294
- * a FAMILY of kinds and is meaningless outside it. A node going away has no
86295
- * device type; a completed export has no package; `stream-offline` deliberately
86296
- * carries no device type at all (a stream belongs to a camera by construction).
86297
- *
86298
- * The engine applied all four to every kind, so a filter from one family failed
86299
- * a kind from another family CLOSED. The operator's live rule "Eventi di
86300
- * sistema" selected eleven kinds and set `deviceTypes: ['camera']` — the only
86301
- * way to say "only my cameras" about the two liveness kinds — and NINE of the
86302
- * eleven silently stopped being deliverable. Four days of history contained
86303
- * `device-online` and `device-offline` and nothing else, across a window in
86304
- * which agents were restarted and addons were updated.
86305
- *
86306
- * Both editors already computed this scoping, to decide which filter boxes to
86307
- * render; the cap's own docblock already promised it ("Narrow a `device-*` kind
86308
- * to these device TYPES"). Only the engine disagreed, and it disagreed in the
86309
- * destructive direction. So the rule is stated ONCE, here, and the engine and
86310
- * the editors are readers of it rather than three independent authors.
86311
- *
86312
- * ── The direction ─────────────────────────────────────────────────────────
86313
- * Out of family ⇒ the filter is IGNORED, never fail-closed. An editor that
86314
- * hides a box has already told the operator this filter does not speak about
86315
- * these kinds, so honouring it as an exclusion contradicts the only
86316
- * explanation the operator was ever given. Inside its family the filter still
86317
- * narrows, and still fails CLOSED on a subject that cannot produce the identity
86318
- * it tests (a device the mirror cannot name is not evidence of a camera).
86319
- */
89169
+ new Set(NC_LEGACY_SYSTEM_EVENT_KINDS);
86320
89170
  /**
86321
89171
  * Every filter, for the callers that must cover all of them (guards, tests).
86322
89172
  *
@@ -86342,9 +89192,6 @@ new Map(Object.entries({
86342
89192
  "device-battery-normal": "device-events",
86343
89193
  "device-consumable-low": "device-events",
86344
89194
  "device-consumable-normal": "device-events",
86345
- "device-tank-low": "device-events",
86346
- "device-tank-full": "device-events",
86347
- "device-tank-normal": "device-events",
86348
89195
  "stream-online": "device-events",
86349
89196
  "stream-offline": "device-events",
86350
89197
  "detection-blind": "device-events",
@@ -86421,16 +89268,6 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
86421
89268
  label: "Consumables",
86422
89269
  kinds: ["device-consumable-low", "device-consumable-normal"]
86423
89270
  },
86424
- {
86425
- id: "tanks",
86426
- family: "device-events",
86427
- label: "Tanks",
86428
- kinds: [
86429
- "device-tank-low",
86430
- "device-tank-full",
86431
- "device-tank-normal"
86432
- ]
86433
- },
86434
89271
  {
86435
89272
  id: "detection-blind",
86436
89273
  family: "device-events",
@@ -86588,11 +89425,6 @@ var RULE_BODY_ONLY = ["body"];
86588
89425
  var RULE_TEXT = ["title", "body"];
86589
89426
  var BATTERY = ["device-battery-low", "device-battery-normal"];
86590
89427
  var CONSUMABLE = ["device-consumable-low", "device-consumable-normal"];
86591
- var TANK = [
86592
- "device-tank-low",
86593
- "device-tank-full",
86594
- "device-tank-normal"
86595
- ];
86596
89428
  var ALERT_EPISODE = [
86597
89429
  "alert-critical",
86598
89430
  "alert-error",
@@ -86624,7 +89456,6 @@ var DEVICE_EVENTS = [
86624
89456
  "device-enabled",
86625
89457
  ...BATTERY,
86626
89458
  ...CONSUMABLE,
86627
- ...TANK,
86628
89459
  "stream-online",
86629
89460
  "stream-offline",
86630
89461
  "detection-blind",
@@ -86655,7 +89486,7 @@ var STATE_SUMMARY_SECTION_VARS = [
86655
89486
  {
86656
89487
  name: "summaryStreams",
86657
89488
  label: "Summary: streams offline",
86658
- example: "Ingresso (high) — since 06:40",
89489
+ example: "Front door (high) — since 06:40",
86659
89490
  kinds: ["stream-offline", "stream-online"]
86660
89491
  },
86661
89492
  {
@@ -86670,22 +89501,16 @@ var STATE_SUMMARY_SECTION_VARS = [
86670
89501
  example: "Robot — filter 10 %",
86671
89502
  kinds: CONSUMABLE
86672
89503
  },
86673
- {
86674
- name: "summaryTanks",
86675
- label: "Summary: tanks",
86676
- example: "Robot — clean water low",
86677
- kinds: TANK
86678
- },
86679
89504
  {
86680
89505
  name: "summaryDetection",
86681
89506
  label: "Summary: cameras detecting nothing",
86682
- example: "Ingresso — since 05:10",
89507
+ example: "Front door — since 05:10",
86683
89508
  kinds: ["detection-blind"]
86684
89509
  },
86685
89510
  {
86686
89511
  name: "summaryNodes",
86687
89512
  label: "Summary: nodes",
86688
- example: "little-unraid — offline since 03:00",
89513
+ example: "agent-a — offline since 03:00",
86689
89514
  kinds: [
86690
89515
  "node-offline",
86691
89516
  "node-online",
@@ -86791,8 +89616,7 @@ var STATE_SUMMARY_VARS = [
86791
89616
  ([...RULE_TEXT], [...COMBINED_ALARM]),
86792
89617
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
86793
89618
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
86794
- ([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
86795
- ([...RULE_TEXT], [...TANK]),
89619
+ ([...RULE_TEXT], [...CONSUMABLE]),
86796
89620
  [...RULE_TEXT],
86797
89621
  ([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
86798
89622
  ([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
@@ -86896,15 +89720,6 @@ new Map([
86896
89720
  snapshotLabel: "Consumables low now",
86897
89721
  snapshotSection: "consumables"
86898
89722
  },
86899
- {
86900
- id: "tanks",
86901
- family: "device-events",
86902
- label: "Tanks (low or full / back to normal)",
86903
- bad: ["device-tank-low", "device-tank-full"],
86904
- recovery: ["device-tank-normal"],
86905
- snapshotLabel: "Tanks low or full now",
86906
- snapshotSection: "tanks"
86907
- },
86908
89723
  {
86909
89724
  id: "motion-noise",
86910
89725
  family: "device-events",
@@ -87357,6 +90172,10 @@ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
87357
90172
  function providerMotionEvent(source, data) {
87358
90173
  return createEvent(EventCategory.ProviderMotion, source, data);
87359
90174
  }
90175
+ Object.freeze({
90176
+ person: .8,
90177
+ vehicle: .8
90178
+ });
87360
90179
  object({
87361
90180
  /**
87362
90181
  * Fraction of the box's own size added on EACH side before cutting.
@@ -188587,7 +191406,7 @@ var REOLINK_ADDON_ID = "provider-reolink";
188587
191406
  * TWO vocabularies arrive here and both must be keyed. The simple-event push
188588
191407
  * (cmd 33 `<AItype>`) says `animal`; the capability probe (cmd 299
188589
191408
  * `getAiDetectTypes`) says `dog_cat` for the same class. Keying only the first
188590
- * made `buildSupportedClasses` drop it, so camera 618 reported
191409
+ * made `buildSupportedClasses` drop it, so camera 108 reported
188591
191410
  * `supportedClasses: ["person","vehicle"]` while its own `lastByClass` held a
188592
191411
  * live `animal` detection — the camera detected a class the system said it
188593
191412
  * could not. The two key-spaces do not collide, so one map serves both.
@@ -188672,7 +191491,7 @@ var reolinkCameraSchema = object({
188672
191491
  *
188673
191492
  * Empty = nothing configured, and `goHome` then REFUSES. It used to go to a
188674
191493
  * hardcoded slot on a vendor "convention" this fleet contradicts: reolink
188675
- * went to preset 0, which on device 592 holds "stanza"; amcrest went to
191494
+ * went to preset 0, which on device 107 holds "stanza"; amcrest went to
188676
191495
  * preset 1, which on device 3836 holds "Preset1". Both swallowed the failure
188677
191496
  * in a bare catch, so a head that never moved was indistinguishable from a
188678
191497
  * head that went home.
@@ -189591,7 +192410,7 @@ var UID_MISSING_REASON = "uid-missing: the hub selects a child by uid, and this
189591
192410
  *
189592
192411
  * - a **closed day** cannot gain or lose a recording, so its listing is
189593
192412
  * immutable for {@link CLOSED_DAY_TTL_MS}. Re-listing yesterday on every
189594
- * scroll would cost 2.0 s of camera time (measured: 546 clips on 592) for an
192413
+ * scroll would cost 2.0 s of camera time (measured: 546 clips on 107) for an
189595
192414
  * answer that cannot have changed;
189596
192415
  * - **today** is `serve-and-revalidate` under `OPERATOR_WRITTEN_STALE_MS` —
189597
192416
  * the same discipline every other Reolink read uses (D224), for the same
@@ -194341,7 +197160,7 @@ function buildClipRefreshDeviceSection(input) {
194341
197160
  *
194342
197161
  * `failure-contribution` keeps `variant` for a second dimension WITHIN a
194343
197162
  * family, and here the useful one is the format the caller pushed: an operator
194344
- * asking "why is 617 silent" needs to know whether HomeKit's Opus or Alexa's
197163
+ * asking "why is 102 silent" needs to know whether HomeKit's Opus or Alexa's
194345
197164
  * raw PCM is the half that is failing. The provider is handed that value on
194346
197165
  * every call, so it is reported rather than guessed — absent, never invented.
194347
197166
  *
@@ -195685,7 +198504,7 @@ async function refreshSnapshotCacheOnce(input) {
195685
198504
  * `logger.child(stableId).withTags({ deviceId })` with the NUMERIC id
195686
198505
  * (`device-cap-proxy.ts`), and `ScopedLogger` merges its bound tags into every
195687
198506
  * line. So every line these channels admit carries `tags.deviceId`, and
195688
- * `| json | deviceId="617"` selects exactly one camera. That is the repo rule
198507
+ * `| json | deviceId="102"` selects exactly one camera. That is the repo rule
195689
198508
  * from `CLAUDE.md` — paid for with a 22% thumbnail gap and a 3-hour media
195690
198509
  * blackout diagnosed by hand — finally paying out.
195691
198510
  *
@@ -195789,7 +198608,7 @@ function capDayNightModeToReolink(mode) {
195789
198608
  * `battery-operated` is derived from the probe flag **OR** the driver's own
195790
198609
  * `isBattery` discriminator — never the probe alone. The probe slice is
195791
198610
  * written only by a SUCCESSFUL `feature-probe` round-trip, and a battery
195792
- * camera that is asleep (or flat, or off-LAN) never answers one: device 640
198611
+ * camera that is asleep (or flat, or off-LAN) never answers one: device 106
195793
198612
  * "Baby monitor" held `deviceCache.deviceType === 'battery-cam'`, a
195794
198613
  * `battery` runtime slice reporting `sleeping: true`, and STILL published
195795
198614
  * `features = ['native-snapshot','rebootable']` because the `feature-probe`
@@ -195800,7 +198619,7 @@ function capDayNightModeToReolink(mode) {
195800
198619
  * map) — without it the camera is drawn as an ordinary awake camera;
195801
198620
  * - the snapshot wrapper's sleep gate (`snapshot.addon.ts`
195802
198621
  * `lookupDeviceMeta().isBattery`) — without it every thumbnail refresh
195803
- * issues a Baichuan login and WAKES the camera (observed hourly on 640
198622
+ * issues a Baichuan login and WAKES the camera (observed hourly on 106
195804
198623
  * while it sat at 14%);
195805
198624
  * - the broker's `preBufferSec = 0` battery rule and its relaxed stall
195806
198625
  * watchdog.
@@ -198863,7 +201682,7 @@ function isNativeObjectForwardingEnabled(capState) {
198863
201682
  * closure inside `registerNativeObjectDetectionCap` had a test that
198864
201683
  * RE-IMPLEMENTED it — and the copy encoded the `dog_cat` gap as intent
198865
201684
  * ("skips unknown Baichuan type names"), so the suite stayed green while
198866
- * camera 618 reported it could not detect a class it was detecting. One
201685
+ * camera 108 reported it could not detect a class it was detecting. One
198867
201686
  * function, one test, no copy.
198868
201687
  *
198869
201688
  * An absent probe is not an empty answer: it means nobody has asked the camera
@@ -199725,7 +202544,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
199725
202544
  * dispatched N times on the camstack side, and `offSimpleEvent`
199726
202545
  * couldn't remove the old one without the original ref. Net
199727
202546
  * effect was that subscriptions drifted out of sync with the
199728
- * camera's TCP push channel: device 15 (Daniel) went silent for
202547
+ * camera's TCP push channel: device 15 (Carol) went silent for
199729
202548
  * 2+ hours while device 8 (battery doorbell) kept pushing
199730
202549
  * normally because its short connection lifecycle naturally
199731
202550
  * reset the listener set.
@@ -200745,7 +203564,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
200745
203564
  }
200746
203565
  /**
200747
203566
  * Arm Baichuan HaCfg (cmd 807) so this battery camera POSTs wake/sleep
200748
- * events to the provider's HTTP intake. Mirrors Scrypted's
203567
+ * events to the provider's HTTP intake. Mirrors plugin catalog's
200749
203568
  * `autoConfigureBaichuanWebhook` — never called from init.
200750
203569
  */
200751
203570
  async autoConfigureBaichuanWebhook() {
@@ -204202,7 +207021,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
204202
207021
  /**
204203
207022
  * Synthesize the HTTP-FLV pull URL for a (channel, profile) pair. FLV is
204204
207023
  * served off the Reolink Baichuan media port (default 1935, app `bcs`) as
204205
- * `channel<channel>_<profile>.bcs` — the same shape go2rtc uses. The
207024
+ * `channel<channel>_<profile>.bcs` — the same shape restreamer uses. The
204206
207025
  * lib does NOT surface this URL, so we build it from the SAME connection
204207
207026
  * creds the RTSP/native paths use (`host`/`username`/`password` on the
204208
207027
  * device config), URL-encoding the credentials.