@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.mjs CHANGED
@@ -28,7 +28,7 @@ import { URL as URL$1 } from "url";
28
28
  import { spawn as spawn$1 } from "node:child_process";
29
29
  import os, { tmpdir } from "node:os";
30
30
  import { createReadStream } from "node:fs";
31
- //#region ../types/dist/event-category-BfJwUd2S.mjs
31
+ //#region ../types/dist/event-category-DHXxB8t9.mjs
32
32
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
33
33
  EventCategory["SystemBoot"] = "system.boot";
34
34
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -324,7 +324,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
324
324
  * TRANSITION into that state (never per dispatch), and the node is dropped
325
325
  * from the placement candidate set for as long as it holds.
326
326
  *
327
- * This exists because the state was previously invisible: little-unraid
327
+ * This exists because the state was previously invisible: agent-a
328
328
  * absorbed 283k inference errors in a day while still being handed cameras,
329
329
  * and nothing in the system said so.
330
330
  *
@@ -355,9 +355,8 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
355
355
  EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
356
356
  /**
357
357
  * Per-camera pipeline config was mutated by the orchestrator
358
- * (3-level settings change via `setAgentAddonDefaults` /
359
- * `setCameraStepToggle` / `setCameraPipelineForAgent` or a
360
- * pipeline-scoped `applyDeviceSettingsPatch`). Orchestrator
358
+ * (a settings change via `setAgentInferenceDevices` /
359
+ * `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
361
360
  * subscribes to its own emission to hot-reload the assigned runner
362
361
  * via `attachCamera` so the next frame executes against the new
363
362
  * engine/steps without waiting for a rebalance or the next
@@ -501,6 +500,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
501
500
  * on the device detail page.
502
501
  */
503
502
  EventCategory["DoorbellOnPressed"] = "doorbell.onPressed";
503
+ /** Mirrors `runningStateCapability.events.onStarted`. */
504
+ EventCategory["RunningStarted"] = "running.started";
505
+ /** Mirrors `runningStateCapability.events.onFinished`. */
506
+ EventCategory["RunningFinished"] = "running.finished";
504
507
  /**
505
508
  * Cap event fired by every device that registers the `event-emitter`
506
509
  * capability. Mirrors `eventEmitterCapability.events.onEvent`. Carries
@@ -5460,7 +5463,7 @@ var ZodIssueCode = {
5460
5463
  var ZodFirstPartyTypeKind;
5461
5464
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5462
5465
  //#endregion
5463
- //#region ../types/dist/sleep-6AqUnQIT.mjs
5466
+ //#region ../types/dist/sleep-BErAxhul.mjs
5464
5467
  /**
5465
5468
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5466
5469
  * window to float samples (D455).
@@ -5803,7 +5806,7 @@ Object.fromEntries([
5803
5806
  * `hydrateSchema` to skip the `value` injection for structural-only fields.
5804
5807
  */
5805
5808
  function isValuelessField(field) {
5806
- 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";
5809
+ 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";
5807
5810
  }
5808
5811
  function hydrateSchema(schema, values, options = {}) {
5809
5812
  return {
@@ -8521,6 +8524,1980 @@ method(object({ deviceId: number() }), array(StreamSourceEntrySchema)), method(o
8521
8524
  kind: "mutation",
8522
8525
  auth: "admin"
8523
8526
  }), method(object({ deviceId: number() }), unknown().nullable()), method(object({ deviceId: number() }), RawStateResultSchema.nullable(), { auth: "protected" });
8527
+ Object.freeze({ "doorbell": "lastPressedAt" });
8528
+ /** Every capability name, so addon code can check a name without the schema graph. */
8529
+ var CAP_NAMES = Object.freeze([
8530
+ "accessories",
8531
+ "addon-pages",
8532
+ "addon-pages-source",
8533
+ "addon-routes",
8534
+ "addon-settings",
8535
+ "addon-widgets",
8536
+ "addon-widgets-source",
8537
+ "addons",
8538
+ "admin-ui",
8539
+ "air-quality-sensor",
8540
+ "alarm-panel",
8541
+ "alerts",
8542
+ "ambient-light-sensor",
8543
+ "audio-analysis",
8544
+ "audio-analyzer",
8545
+ "audio-codec",
8546
+ "audio-metrics",
8547
+ "auth-provider",
8548
+ "automation-control",
8549
+ "backup",
8550
+ "battery",
8551
+ "binary",
8552
+ "brightness",
8553
+ "broker",
8554
+ "button",
8555
+ "calendar-source",
8556
+ "calendars",
8557
+ "camera-credentials",
8558
+ "camera-grid-layout",
8559
+ "camera-pipeline-config",
8560
+ "camera-streams",
8561
+ "carbon-monoxide",
8562
+ "climate-control",
8563
+ "color",
8564
+ "composer",
8565
+ "connection-test",
8566
+ "connectivity",
8567
+ "consumables",
8568
+ "contact",
8569
+ "control",
8570
+ "core-blocks",
8571
+ "cover",
8572
+ "custom-model-registry",
8573
+ "data-store-provider",
8574
+ "database-snapshot",
8575
+ "day-night",
8576
+ "decoder",
8577
+ "detection-pipeline",
8578
+ "device-admin-link",
8579
+ "device-adoption",
8580
+ "device-credentials",
8581
+ "device-discovery",
8582
+ "device-export",
8583
+ "device-extension",
8584
+ "device-history",
8585
+ "device-manager",
8586
+ "device-ops",
8587
+ "device-provider",
8588
+ "device-removal-hook",
8589
+ "device-state",
8590
+ "device-status",
8591
+ "dishwasher",
8592
+ "display-palette",
8593
+ "doorbell",
8594
+ "embedding-encoder",
8595
+ "enum-sensor",
8596
+ "event-emitter",
8597
+ "face-gallery",
8598
+ "failure-contribution",
8599
+ "fan-control",
8600
+ "feature-probe",
8601
+ "filesystem-browse",
8602
+ "flood",
8603
+ "gas",
8604
+ "heating-valve",
8605
+ "humidifier",
8606
+ "humidity-sensor",
8607
+ "image",
8608
+ "image-settings",
8609
+ "integrations",
8610
+ "intercom",
8611
+ "keychain",
8612
+ "keychain-admin",
8613
+ "lawn-mower-control",
8614
+ "llm",
8615
+ "llm-runtime",
8616
+ "load-contribution",
8617
+ "local-network",
8618
+ "lock-control",
8619
+ "log-channels",
8620
+ "log-destination",
8621
+ "login-method",
8622
+ "media-player",
8623
+ "mesh-network",
8624
+ "metrics-provider",
8625
+ "model-convert",
8626
+ "model-distributor",
8627
+ "motion",
8628
+ "motion-detection",
8629
+ "motion-trigger",
8630
+ "motion-zones",
8631
+ "mqtt-broker",
8632
+ "native-object-detection",
8633
+ "navigation",
8634
+ "network-access",
8635
+ "network-link",
8636
+ "network-quality",
8637
+ "node-certificates",
8638
+ "nodes",
8639
+ "notification-output",
8640
+ "notification-rules",
8641
+ "notifier",
8642
+ "numeric-sensor",
8643
+ "oauth-integration",
8644
+ "oidc-connections",
8645
+ "osd",
8646
+ "osd-manager",
8647
+ "pet-feeder",
8648
+ "pipeline-analytics",
8649
+ "pipeline-executor",
8650
+ "pipeline-orchestrator",
8651
+ "pipeline-runner",
8652
+ "plate-gallery",
8653
+ "platform-probe",
8654
+ "power-meter",
8655
+ "presence",
8656
+ "pressure-sensor",
8657
+ "privacy-mask",
8658
+ "ptz",
8659
+ "ptz-autotrack",
8660
+ "reboot",
8661
+ "record-entries",
8662
+ "recording",
8663
+ "recording-archive",
8664
+ "recording-export",
8665
+ "recording-onboard",
8666
+ "recording-signal",
8667
+ "records",
8668
+ "running-state",
8669
+ "scene-monitor",
8670
+ "script-runner",
8671
+ "server-management",
8672
+ "settings-store",
8673
+ "smoke",
8674
+ "smtp-provider",
8675
+ "snapshot",
8676
+ "sso-bridge",
8677
+ "storage",
8678
+ "storage-admin",
8679
+ "storage-evictable",
8680
+ "storage-migration",
8681
+ "storage-occupancy",
8682
+ "storage-provider",
8683
+ "stream-broker",
8684
+ "stream-catalog",
8685
+ "stream-params",
8686
+ "stream-signals",
8687
+ "switch",
8688
+ "system",
8689
+ "tamper",
8690
+ "temperature-sensor",
8691
+ "terminal-session",
8692
+ "toast",
8693
+ "training",
8694
+ "training-provider",
8695
+ "turn-provider",
8696
+ "update",
8697
+ "user-management",
8698
+ "user-passkeys",
8699
+ "vacuum-control",
8700
+ "valve",
8701
+ "vector-store",
8702
+ "vibration",
8703
+ "videoclips",
8704
+ "viewer-ui",
8705
+ "water-heater",
8706
+ "weather",
8707
+ "webrtc-session",
8708
+ "zone-analytics",
8709
+ "zone-rules",
8710
+ "zones"
8711
+ ]);
8712
+ Object.freeze({
8713
+ "air-quality-sensor": [
8714
+ {
8715
+ "path": "co2Ppm",
8716
+ "valueType": "number"
8717
+ },
8718
+ {
8719
+ "path": "vocPpb",
8720
+ "valueType": "number"
8721
+ },
8722
+ {
8723
+ "path": "pm25",
8724
+ "valueType": "number"
8725
+ },
8726
+ {
8727
+ "path": "pm10",
8728
+ "valueType": "number"
8729
+ },
8730
+ {
8731
+ "path": "aqi",
8732
+ "valueType": "number"
8733
+ },
8734
+ {
8735
+ "path": "unit",
8736
+ "valueType": "string"
8737
+ },
8738
+ {
8739
+ "path": "precision",
8740
+ "valueType": "number"
8741
+ }
8742
+ ],
8743
+ "alarm-panel": [
8744
+ {
8745
+ "path": "state",
8746
+ "valueType": "enum",
8747
+ "enumValues": [
8748
+ "disarmed",
8749
+ "armed_home",
8750
+ "armed_away",
8751
+ "armed_night",
8752
+ "armed_vacation",
8753
+ "armed_custom_bypass",
8754
+ "arming",
8755
+ "disarming",
8756
+ "pending",
8757
+ "triggered"
8758
+ ]
8759
+ },
8760
+ {
8761
+ "path": "targetMode",
8762
+ "valueType": "enum",
8763
+ "enumValues": [
8764
+ "home",
8765
+ "away",
8766
+ "night",
8767
+ "vacation",
8768
+ "custom_bypass"
8769
+ ]
8770
+ },
8771
+ {
8772
+ "path": "requiresCode",
8773
+ "valueType": "boolean"
8774
+ }
8775
+ ],
8776
+ "ambient-light-sensor": [
8777
+ {
8778
+ "path": "lux",
8779
+ "valueType": "number"
8780
+ },
8781
+ {
8782
+ "path": "unit",
8783
+ "valueType": "string"
8784
+ },
8785
+ {
8786
+ "path": "precision",
8787
+ "valueType": "number"
8788
+ }
8789
+ ],
8790
+ "audio-metrics": [
8791
+ {
8792
+ "path": "ts",
8793
+ "valueType": "number"
8794
+ },
8795
+ {
8796
+ "path": "windowSec",
8797
+ "valueType": "number"
8798
+ },
8799
+ {
8800
+ "path": "level.rms",
8801
+ "valueType": "number"
8802
+ },
8803
+ {
8804
+ "path": "level.dbfs",
8805
+ "valueType": "number"
8806
+ },
8807
+ {
8808
+ "path": "peakDbfs",
8809
+ "valueType": "number"
8810
+ },
8811
+ {
8812
+ "path": "avgDbfs",
8813
+ "valueType": "number"
8814
+ },
8815
+ {
8816
+ "path": "current.className",
8817
+ "valueType": "string"
8818
+ },
8819
+ {
8820
+ "path": "current.score",
8821
+ "valueType": "number"
8822
+ },
8823
+ {
8824
+ "path": "current.timestamp",
8825
+ "valueType": "number"
8826
+ }
8827
+ ],
8828
+ "automation-control": [
8829
+ {
8830
+ "path": "enabled",
8831
+ "valueType": "boolean"
8832
+ },
8833
+ {
8834
+ "path": "isRunning",
8835
+ "valueType": "boolean"
8836
+ },
8837
+ {
8838
+ "path": "lastTriggeredAt",
8839
+ "valueType": "number"
8840
+ },
8841
+ {
8842
+ "path": "lastError",
8843
+ "valueType": "string"
8844
+ }
8845
+ ],
8846
+ "battery": [
8847
+ {
8848
+ "path": "percentage",
8849
+ "valueType": "number"
8850
+ },
8851
+ {
8852
+ "path": "charging",
8853
+ "valueType": "enum",
8854
+ "enumValues": [
8855
+ "dc",
8856
+ "solar",
8857
+ "none",
8858
+ "unknown"
8859
+ ]
8860
+ },
8861
+ {
8862
+ "path": "sleeping",
8863
+ "valueType": "boolean"
8864
+ },
8865
+ {
8866
+ "path": "lastUpdated",
8867
+ "valueType": "number"
8868
+ },
8869
+ {
8870
+ "path": "lastContactAt",
8871
+ "valueType": "number"
8872
+ },
8873
+ {
8874
+ "path": "lastFullRefreshAt",
8875
+ "valueType": "number"
8876
+ },
8877
+ {
8878
+ "path": "binary",
8879
+ "valueType": "boolean"
8880
+ }
8881
+ ],
8882
+ "binary": [{
8883
+ "path": "on",
8884
+ "valueType": "boolean"
8885
+ }],
8886
+ "brightness": [{
8887
+ "path": "percentage",
8888
+ "valueType": "number"
8889
+ }],
8890
+ "broker": [{
8891
+ "path": "brokerCount",
8892
+ "valueType": "number"
8893
+ }, {
8894
+ "path": "connectedCount",
8895
+ "valueType": "number"
8896
+ }],
8897
+ "camera-credentials": [
8898
+ {
8899
+ "path": "host",
8900
+ "valueType": "string"
8901
+ },
8902
+ {
8903
+ "path": "port",
8904
+ "valueType": "number"
8905
+ },
8906
+ {
8907
+ "path": "onvifPort",
8908
+ "valueType": "number"
8909
+ },
8910
+ {
8911
+ "path": "rtspPort",
8912
+ "valueType": "number"
8913
+ },
8914
+ {
8915
+ "path": "https",
8916
+ "valueType": "boolean"
8917
+ },
8918
+ {
8919
+ "path": "hasUsername",
8920
+ "valueType": "boolean"
8921
+ },
8922
+ {
8923
+ "path": "hasPassword",
8924
+ "valueType": "boolean"
8925
+ },
8926
+ {
8927
+ "path": "onvifProfile",
8928
+ "valueType": "string"
8929
+ }
8930
+ ],
8931
+ "camera-streams": [
8932
+ {
8933
+ "path": "online",
8934
+ "valueType": "boolean"
8935
+ },
8936
+ {
8937
+ "path": "slotStatuses.high",
8938
+ "valueType": "enum",
8939
+ "enumValues": [
8940
+ "unassigned",
8941
+ "idle",
8942
+ "connecting",
8943
+ "streaming",
8944
+ "error"
8945
+ ]
8946
+ },
8947
+ {
8948
+ "path": "slotStatuses.mid",
8949
+ "valueType": "enum",
8950
+ "enumValues": [
8951
+ "unassigned",
8952
+ "idle",
8953
+ "connecting",
8954
+ "streaming",
8955
+ "error"
8956
+ ]
8957
+ },
8958
+ {
8959
+ "path": "slotStatuses.low",
8960
+ "valueType": "enum",
8961
+ "enumValues": [
8962
+ "unassigned",
8963
+ "idle",
8964
+ "connecting",
8965
+ "streaming",
8966
+ "error"
8967
+ ]
8968
+ },
8969
+ {
8970
+ "path": "slotErrors.high",
8971
+ "valueType": "string"
8972
+ },
8973
+ {
8974
+ "path": "slotErrors.mid",
8975
+ "valueType": "string"
8976
+ },
8977
+ {
8978
+ "path": "slotErrors.low",
8979
+ "valueType": "string"
8980
+ }
8981
+ ],
8982
+ "carbon-monoxide": [{
8983
+ "path": "detected",
8984
+ "valueType": "boolean"
8985
+ }],
8986
+ "climate-control": [
8987
+ {
8988
+ "path": "mode",
8989
+ "valueType": "enum",
8990
+ "enumValues": [
8991
+ "off",
8992
+ "heat",
8993
+ "cool",
8994
+ "auto",
8995
+ "heat_cool",
8996
+ "fan_only",
8997
+ "dry"
8998
+ ]
8999
+ },
9000
+ {
9001
+ "path": "fanMode",
9002
+ "valueType": "string"
9003
+ },
9004
+ {
9005
+ "path": "preset",
9006
+ "valueType": "string"
9007
+ },
9008
+ {
9009
+ "path": "target",
9010
+ "valueType": "number"
9011
+ },
9012
+ {
9013
+ "path": "targetHigh",
9014
+ "valueType": "number"
9015
+ },
9016
+ {
9017
+ "path": "targetLow",
9018
+ "valueType": "number"
9019
+ },
9020
+ {
9021
+ "path": "targetHumidity",
9022
+ "valueType": "number"
9023
+ },
9024
+ {
9025
+ "path": "currentTemp",
9026
+ "valueType": "number"
9027
+ },
9028
+ {
9029
+ "path": "currentHumidity",
9030
+ "valueType": "number"
9031
+ },
9032
+ {
9033
+ "path": "swingVertical",
9034
+ "valueType": "boolean"
9035
+ },
9036
+ {
9037
+ "path": "swingHorizontal",
9038
+ "valueType": "boolean"
9039
+ },
9040
+ {
9041
+ "path": "minTemp",
9042
+ "valueType": "number"
9043
+ },
9044
+ {
9045
+ "path": "maxTemp",
9046
+ "valueType": "number"
9047
+ },
9048
+ {
9049
+ "path": "tempStep",
9050
+ "valueType": "number"
9051
+ }
9052
+ ],
9053
+ "color": [
9054
+ {
9055
+ "path": "mode",
9056
+ "valueType": "enum",
9057
+ "enumValues": [
9058
+ "rgb",
9059
+ "hsv",
9060
+ "mired"
9061
+ ]
9062
+ },
9063
+ {
9064
+ "path": "rgb.r",
9065
+ "valueType": "number"
9066
+ },
9067
+ {
9068
+ "path": "rgb.g",
9069
+ "valueType": "number"
9070
+ },
9071
+ {
9072
+ "path": "rgb.b",
9073
+ "valueType": "number"
9074
+ },
9075
+ {
9076
+ "path": "hsv.h",
9077
+ "valueType": "number"
9078
+ },
9079
+ {
9080
+ "path": "hsv.s",
9081
+ "valueType": "number"
9082
+ },
9083
+ {
9084
+ "path": "hsv.v",
9085
+ "valueType": "number"
9086
+ },
9087
+ {
9088
+ "path": "mireds",
9089
+ "valueType": "number"
9090
+ }
9091
+ ],
9092
+ "connectivity": [{
9093
+ "path": "connected",
9094
+ "valueType": "boolean"
9095
+ }],
9096
+ "contact": [{
9097
+ "path": "entryOpen",
9098
+ "valueType": "boolean"
9099
+ }],
9100
+ "control": [
9101
+ {
9102
+ "path": "kind",
9103
+ "valueType": "enum",
9104
+ "enumValues": [
9105
+ "numeric",
9106
+ "select",
9107
+ "text",
9108
+ "datetime"
9109
+ ]
9110
+ },
9111
+ {
9112
+ "path": "unit",
9113
+ "valueType": "string"
9114
+ },
9115
+ {
9116
+ "path": "min",
9117
+ "valueType": "number"
9118
+ },
9119
+ {
9120
+ "path": "max",
9121
+ "valueType": "number"
9122
+ },
9123
+ {
9124
+ "path": "step",
9125
+ "valueType": "number"
9126
+ },
9127
+ {
9128
+ "path": "precision",
9129
+ "valueType": "number"
9130
+ },
9131
+ {
9132
+ "path": "format",
9133
+ "valueType": "enum",
9134
+ "enumValues": [
9135
+ "date",
9136
+ "time",
9137
+ "datetime"
9138
+ ]
9139
+ }
9140
+ ],
9141
+ "cover": [
9142
+ {
9143
+ "path": "state",
9144
+ "valueType": "enum",
9145
+ "enumValues": [
9146
+ "open",
9147
+ "opening",
9148
+ "closing",
9149
+ "closed",
9150
+ "stopped"
9151
+ ]
9152
+ },
9153
+ {
9154
+ "path": "position",
9155
+ "valueType": "number"
9156
+ },
9157
+ {
9158
+ "path": "tiltPosition",
9159
+ "valueType": "number"
9160
+ }
9161
+ ],
9162
+ "day-night": [
9163
+ {
9164
+ "path": "mode",
9165
+ "valueType": "enum",
9166
+ "enumValues": [
9167
+ "auto",
9168
+ "day",
9169
+ "night",
9170
+ "schedule"
9171
+ ]
9172
+ },
9173
+ {
9174
+ "path": "sensitivity",
9175
+ "valueType": "number"
9176
+ },
9177
+ {
9178
+ "path": "switchDelaySec",
9179
+ "valueType": "number"
9180
+ }
9181
+ ],
9182
+ "device-adoption": [
9183
+ {
9184
+ "path": "lastDiscoveryAt",
9185
+ "valueType": "number"
9186
+ },
9187
+ {
9188
+ "path": "candidateCount",
9189
+ "valueType": "number"
9190
+ },
9191
+ {
9192
+ "path": "adoptedCount",
9193
+ "valueType": "number"
9194
+ },
9195
+ {
9196
+ "path": "lastError",
9197
+ "valueType": "string"
9198
+ }
9199
+ ],
9200
+ "device-discovery": [{
9201
+ "path": "lastDiscoveryAt",
9202
+ "valueType": "number"
9203
+ }, {
9204
+ "path": "lastError",
9205
+ "valueType": "string"
9206
+ }],
9207
+ "device-export": [
9208
+ {
9209
+ "path": "linkState",
9210
+ "valueType": "enum",
9211
+ "enumValues": [
9212
+ "unlinked",
9213
+ "linked",
9214
+ "error"
9215
+ ]
9216
+ },
9217
+ {
9218
+ "path": "exposedDeviceCount",
9219
+ "valueType": "number"
9220
+ },
9221
+ {
9222
+ "path": "error",
9223
+ "valueType": "string"
9224
+ },
9225
+ {
9226
+ "path": "setup.qr",
9227
+ "valueType": "string"
9228
+ },
9229
+ {
9230
+ "path": "setup.note",
9231
+ "valueType": "string"
9232
+ }
9233
+ ],
9234
+ "device-status": [{
9235
+ "path": "online",
9236
+ "valueType": "boolean"
9237
+ }],
9238
+ "dishwasher": [
9239
+ {
9240
+ "path": "availability",
9241
+ "valueType": "enum",
9242
+ "enumValues": [
9243
+ "available",
9244
+ "offline",
9245
+ "description-missing"
9246
+ ]
9247
+ },
9248
+ {
9249
+ "path": "state",
9250
+ "valueType": "enum",
9251
+ "enumValues": [
9252
+ "idle",
9253
+ "running",
9254
+ "paused",
9255
+ "finished",
9256
+ "error",
9257
+ "unavailable"
9258
+ ]
9259
+ },
9260
+ {
9261
+ "path": "operationState",
9262
+ "valueType": "enum",
9263
+ "enumValues": [
9264
+ "Inactive",
9265
+ "Ready",
9266
+ "DelayedStart",
9267
+ "Run",
9268
+ "Pause",
9269
+ "ActionRequired",
9270
+ "Finished",
9271
+ "Error",
9272
+ "Aborting"
9273
+ ]
9274
+ },
9275
+ {
9276
+ "path": "program",
9277
+ "valueType": "string"
9278
+ },
9279
+ {
9280
+ "path": "selectedProgram",
9281
+ "valueType": "string"
9282
+ },
9283
+ {
9284
+ "path": "remainingSeconds",
9285
+ "valueType": "number"
9286
+ },
9287
+ {
9288
+ "path": "delayedStartSeconds",
9289
+ "valueType": "number"
9290
+ },
9291
+ {
9292
+ "path": "progressPercent",
9293
+ "valueType": "number"
9294
+ },
9295
+ {
9296
+ "path": "doorOpen",
9297
+ "valueType": "boolean"
9298
+ },
9299
+ {
9300
+ "path": "doorLocked",
9301
+ "valueType": "boolean"
9302
+ },
9303
+ {
9304
+ "path": "remoteStartAllowed",
9305
+ "valueType": "boolean"
9306
+ },
9307
+ {
9308
+ "path": "remoteControlActive",
9309
+ "valueType": "boolean"
9310
+ },
9311
+ {
9312
+ "path": "localControlActive",
9313
+ "valueType": "boolean"
9314
+ },
9315
+ {
9316
+ "path": "powerOn",
9317
+ "valueType": "boolean"
9318
+ },
9319
+ {
9320
+ "path": "powerState",
9321
+ "valueType": "string"
9322
+ },
9323
+ {
9324
+ "path": "filterCleaningDue",
9325
+ "valueType": "boolean"
9326
+ },
9327
+ {
9328
+ "path": "machineCareDue",
9329
+ "valueType": "boolean"
9330
+ },
9331
+ {
9332
+ "path": "machineCareRemainingRuns",
9333
+ "valueType": "number"
9334
+ },
9335
+ {
9336
+ "path": "halfLoad",
9337
+ "valueType": "boolean"
9338
+ },
9339
+ {
9340
+ "path": "hygienePlus",
9341
+ "valueType": "boolean"
9342
+ },
9343
+ {
9344
+ "path": "extraDry",
9345
+ "valueType": "boolean"
9346
+ },
9347
+ {
9348
+ "path": "intensiveZone",
9349
+ "valueType": "boolean"
9350
+ },
9351
+ {
9352
+ "path": "varioSpeedPlus",
9353
+ "valueType": "boolean"
9354
+ },
9355
+ {
9356
+ "path": "childLock",
9357
+ "valueType": "boolean"
9358
+ },
9359
+ {
9360
+ "path": "errorCode",
9361
+ "valueType": "number"
9362
+ },
9363
+ {
9364
+ "path": "errorLabel",
9365
+ "valueType": "string"
9366
+ }
9367
+ ],
9368
+ "doorbell": [{
9369
+ "path": "lastPressedAt",
9370
+ "valueType": "number"
9371
+ }, {
9372
+ "path": "pressCountSinceStart",
9373
+ "valueType": "number"
9374
+ }],
9375
+ "enum-sensor": [{
9376
+ "path": "value",
9377
+ "valueType": "string"
9378
+ }, {
9379
+ "path": "format",
9380
+ "valueType": "enum",
9381
+ "enumValues": [
9382
+ "date",
9383
+ "time",
9384
+ "datetime"
9385
+ ]
9386
+ }],
9387
+ "event-emitter": [
9388
+ {
9389
+ "path": "lastEvent.deviceId",
9390
+ "valueType": "number"
9391
+ },
9392
+ {
9393
+ "path": "lastEvent.eventType",
9394
+ "valueType": "string"
9395
+ },
9396
+ {
9397
+ "path": "lastEvent.timestamp",
9398
+ "valueType": "number"
9399
+ },
9400
+ {
9401
+ "path": "lastEvent.seq",
9402
+ "valueType": "number"
9403
+ },
9404
+ {
9405
+ "path": "eventCountSinceStart",
9406
+ "valueType": "number"
9407
+ }
9408
+ ],
9409
+ "fan-control": [
9410
+ {
9411
+ "path": "percentage",
9412
+ "valueType": "number"
9413
+ },
9414
+ {
9415
+ "path": "percentageStep",
9416
+ "valueType": "number"
9417
+ },
9418
+ {
9419
+ "path": "preset",
9420
+ "valueType": "string"
9421
+ },
9422
+ {
9423
+ "path": "direction",
9424
+ "valueType": "enum",
9425
+ "enumValues": ["forward", "reverse"]
9426
+ },
9427
+ {
9428
+ "path": "oscillating",
9429
+ "valueType": "boolean"
9430
+ }
9431
+ ],
9432
+ "feature-probe": [
9433
+ {
9434
+ "path": "deviceType",
9435
+ "valueType": "string"
9436
+ },
9437
+ {
9438
+ "path": "model",
9439
+ "valueType": "string"
9440
+ },
9441
+ {
9442
+ "path": "channelCount",
9443
+ "valueType": "number"
9444
+ },
9445
+ {
9446
+ "path": "lastProbedAt",
9447
+ "valueType": "number"
9448
+ }
9449
+ ],
9450
+ "flood": [{
9451
+ "path": "flooded",
9452
+ "valueType": "boolean"
9453
+ }],
9454
+ "gas": [{
9455
+ "path": "detected",
9456
+ "valueType": "boolean"
9457
+ }],
9458
+ "heating-valve": [{
9459
+ "path": "position",
9460
+ "valueType": "number"
9461
+ }],
9462
+ "humidifier": [
9463
+ {
9464
+ "path": "on",
9465
+ "valueType": "boolean"
9466
+ },
9467
+ {
9468
+ "path": "currentHumidity",
9469
+ "valueType": "number"
9470
+ },
9471
+ {
9472
+ "path": "targetHumidity",
9473
+ "valueType": "number"
9474
+ },
9475
+ {
9476
+ "path": "mode",
9477
+ "valueType": "string"
9478
+ },
9479
+ {
9480
+ "path": "action",
9481
+ "valueType": "string"
9482
+ },
9483
+ {
9484
+ "path": "minHumidity",
9485
+ "valueType": "number"
9486
+ },
9487
+ {
9488
+ "path": "maxHumidity",
9489
+ "valueType": "number"
9490
+ }
9491
+ ],
9492
+ "humidity-sensor": [
9493
+ {
9494
+ "path": "percent",
9495
+ "valueType": "number"
9496
+ },
9497
+ {
9498
+ "path": "unit",
9499
+ "valueType": "string"
9500
+ },
9501
+ {
9502
+ "path": "precision",
9503
+ "valueType": "number"
9504
+ }
9505
+ ],
9506
+ "image": [{
9507
+ "path": "url",
9508
+ "valueType": "string"
9509
+ }, {
9510
+ "path": "lastUpdated",
9511
+ "valueType": "number"
9512
+ }],
9513
+ "image-settings": [
9514
+ {
9515
+ "path": "brightness",
9516
+ "valueType": "number"
9517
+ },
9518
+ {
9519
+ "path": "contrast",
9520
+ "valueType": "number"
9521
+ },
9522
+ {
9523
+ "path": "saturation",
9524
+ "valueType": "number"
9525
+ },
9526
+ {
9527
+ "path": "sharpness",
9528
+ "valueType": "number"
9529
+ },
9530
+ {
9531
+ "path": "mirror",
9532
+ "valueType": "boolean"
9533
+ },
9534
+ {
9535
+ "path": "flip",
9536
+ "valueType": "boolean"
9537
+ },
9538
+ {
9539
+ "path": "rotate",
9540
+ "valueType": "enum",
9541
+ "enumValues": [
9542
+ "0",
9543
+ "90",
9544
+ "180",
9545
+ "270"
9546
+ ]
9547
+ },
9548
+ {
9549
+ "path": "whiteBalance",
9550
+ "valueType": "enum",
9551
+ "enumValues": ["auto", "manual"]
9552
+ },
9553
+ {
9554
+ "path": "warmth",
9555
+ "valueType": "number"
9556
+ },
9557
+ {
9558
+ "path": "exposureMode",
9559
+ "valueType": "enum",
9560
+ "enumValues": ["auto", "manual"]
9561
+ },
9562
+ {
9563
+ "path": "backlightMode",
9564
+ "valueType": "enum",
9565
+ "enumValues": [
9566
+ "off",
9567
+ "blc",
9568
+ "wdr",
9569
+ "hlc"
9570
+ ]
9571
+ }
9572
+ ],
9573
+ "intercom": [
9574
+ {
9575
+ "path": "talking",
9576
+ "valueType": "boolean"
9577
+ },
9578
+ {
9579
+ "path": "lastSessionAt",
9580
+ "valueType": "number"
9581
+ },
9582
+ {
9583
+ "path": "ability.sampleRate",
9584
+ "valueType": "number"
9585
+ },
9586
+ {
9587
+ "path": "ability.duplex",
9588
+ "valueType": "enum",
9589
+ "enumValues": ["half", "full"]
9590
+ },
9591
+ {
9592
+ "path": "ability.maxBacklogMs",
9593
+ "valueType": "number"
9594
+ }
9595
+ ],
9596
+ "lawn-mower-control": [
9597
+ {
9598
+ "path": "activity",
9599
+ "valueType": "enum",
9600
+ "enumValues": [
9601
+ "idle",
9602
+ "mowing",
9603
+ "paused",
9604
+ "docked",
9605
+ "error"
9606
+ ]
9607
+ },
9608
+ {
9609
+ "path": "batteryLevel",
9610
+ "valueType": "number"
9611
+ },
9612
+ {
9613
+ "path": "progressPercent",
9614
+ "valueType": "number"
9615
+ },
9616
+ {
9617
+ "path": "currentCode",
9618
+ "valueType": "number"
9619
+ },
9620
+ {
9621
+ "path": "currentCodeLabel",
9622
+ "valueType": "string"
9623
+ },
9624
+ {
9625
+ "path": "severity",
9626
+ "valueType": "enum",
9627
+ "enumValues": [
9628
+ "info",
9629
+ "warning",
9630
+ "error"
9631
+ ]
9632
+ }
9633
+ ],
9634
+ "lock-control": [{
9635
+ "path": "state",
9636
+ "valueType": "enum",
9637
+ "enumValues": [
9638
+ "locked",
9639
+ "unlocked",
9640
+ "locking",
9641
+ "unlocking",
9642
+ "jammed"
9643
+ ]
9644
+ }],
9645
+ "media-player": [
9646
+ {
9647
+ "path": "state",
9648
+ "valueType": "enum",
9649
+ "enumValues": [
9650
+ "off",
9651
+ "on",
9652
+ "idle",
9653
+ "playing",
9654
+ "paused",
9655
+ "buffering",
9656
+ "standby"
9657
+ ]
9658
+ },
9659
+ {
9660
+ "path": "volumeLevel",
9661
+ "valueType": "number"
9662
+ },
9663
+ {
9664
+ "path": "isMuted",
9665
+ "valueType": "boolean"
9666
+ },
9667
+ {
9668
+ "path": "source",
9669
+ "valueType": "string"
9670
+ },
9671
+ {
9672
+ "path": "currentMedia.type",
9673
+ "valueType": "string"
9674
+ },
9675
+ {
9676
+ "path": "currentMedia.title",
9677
+ "valueType": "string"
9678
+ },
9679
+ {
9680
+ "path": "currentMedia.artist",
9681
+ "valueType": "string"
9682
+ },
9683
+ {
9684
+ "path": "currentMedia.album",
9685
+ "valueType": "string"
9686
+ },
9687
+ {
9688
+ "path": "currentMedia.imageUrl",
9689
+ "valueType": "string"
9690
+ },
9691
+ {
9692
+ "path": "positionMs",
9693
+ "valueType": "number"
9694
+ },
9695
+ {
9696
+ "path": "durationMs",
9697
+ "valueType": "number"
9698
+ },
9699
+ {
9700
+ "path": "shuffle",
9701
+ "valueType": "boolean"
9702
+ },
9703
+ {
9704
+ "path": "repeat",
9705
+ "valueType": "enum",
9706
+ "enumValues": [
9707
+ "off",
9708
+ "all",
9709
+ "one"
9710
+ ]
9711
+ }
9712
+ ],
9713
+ "motion": [
9714
+ {
9715
+ "path": "detected",
9716
+ "valueType": "boolean"
9717
+ },
9718
+ {
9719
+ "path": "lastDetectedAt",
9720
+ "valueType": "number"
9721
+ },
9722
+ {
9723
+ "path": "autoClearAfterMs",
9724
+ "valueType": "number"
9725
+ }
9726
+ ],
9727
+ "motion-trigger": [{
9728
+ "path": "enabled",
9729
+ "valueType": "boolean"
9730
+ }],
9731
+ "motion-zones": [{
9732
+ "path": "enabled",
9733
+ "valueType": "boolean"
9734
+ }, {
9735
+ "path": "sensitivity",
9736
+ "valueType": "number"
9737
+ }],
9738
+ "mqtt-broker": [{
9739
+ "path": "brokerCount",
9740
+ "valueType": "number"
9741
+ }, {
9742
+ "path": "embeddedRunning",
9743
+ "valueType": "boolean"
9744
+ }],
9745
+ "native-object-detection": [{
9746
+ "path": "enabled",
9747
+ "valueType": "boolean"
9748
+ }],
9749
+ "navigation": [
9750
+ {
9751
+ "path": "mode",
9752
+ "valueType": "enum",
9753
+ "enumValues": [
9754
+ "idle",
9755
+ "cleaning",
9756
+ "spot",
9757
+ "following",
9758
+ "goto",
9759
+ "returning",
9760
+ "paused",
9761
+ "unknown"
9762
+ ]
9763
+ },
9764
+ {
9765
+ "path": "following",
9766
+ "valueType": "boolean"
9767
+ },
9768
+ {
9769
+ "path": "flash",
9770
+ "valueType": "boolean"
9771
+ },
9772
+ {
9773
+ "path": "lightMode",
9774
+ "valueType": "enum",
9775
+ "enumValues": ["auto", "manual"]
9776
+ },
9777
+ {
9778
+ "path": "lightLevel",
9779
+ "valueType": "number"
9780
+ }
9781
+ ],
9782
+ "network-link": [
9783
+ {
9784
+ "path": "type",
9785
+ "valueType": "enum",
9786
+ "enumValues": [
9787
+ "wifi",
9788
+ "ethernet",
9789
+ "cellular",
9790
+ "unknown"
9791
+ ]
9792
+ },
9793
+ {
9794
+ "path": "signalPercent",
9795
+ "valueType": "number"
9796
+ },
9797
+ {
9798
+ "path": "rssiDbm",
9799
+ "valueType": "number"
9800
+ },
9801
+ {
9802
+ "path": "ssid",
9803
+ "valueType": "string"
9804
+ },
9805
+ {
9806
+ "path": "lastUpdated",
9807
+ "valueType": "number"
9808
+ }
9809
+ ],
9810
+ "notifier": [
9811
+ {
9812
+ "path": "lastSentAt",
9813
+ "valueType": "number"
9814
+ },
9815
+ {
9816
+ "path": "lastError",
9817
+ "valueType": "string"
9818
+ },
9819
+ {
9820
+ "path": "queueDepth",
9821
+ "valueType": "number"
9822
+ },
9823
+ {
9824
+ "path": "supports.image",
9825
+ "valueType": "boolean"
9826
+ },
9827
+ {
9828
+ "path": "supports.priority",
9829
+ "valueType": "boolean"
9830
+ },
9831
+ {
9832
+ "path": "supports.data",
9833
+ "valueType": "boolean"
9834
+ },
9835
+ {
9836
+ "path": "supports.actions",
9837
+ "valueType": "boolean"
9838
+ },
9839
+ {
9840
+ "path": "supports.recipients",
9841
+ "valueType": "boolean"
9842
+ }
9843
+ ],
9844
+ "numeric-sensor": [
9845
+ {
9846
+ "path": "value",
9847
+ "valueType": "number"
9848
+ },
9849
+ {
9850
+ "path": "unit",
9851
+ "valueType": "string"
9852
+ },
9853
+ {
9854
+ "path": "precision",
9855
+ "valueType": "number"
9856
+ }
9857
+ ],
9858
+ "pet-feeder": [
9859
+ {
9860
+ "path": "foodLevel",
9861
+ "valueType": "number"
9862
+ },
9863
+ {
9864
+ "path": "food1",
9865
+ "valueType": "number"
9866
+ },
9867
+ {
9868
+ "path": "food2",
9869
+ "valueType": "number"
9870
+ },
9871
+ {
9872
+ "path": "lowFood",
9873
+ "valueType": "boolean"
9874
+ },
9875
+ {
9876
+ "path": "batteryPower",
9877
+ "valueType": "number"
9878
+ },
9879
+ {
9880
+ "path": "desiccantLeftDays",
9881
+ "valueType": "number"
9882
+ },
9883
+ {
9884
+ "path": "feeding",
9885
+ "valueType": "boolean"
9886
+ },
9887
+ {
9888
+ "path": "status",
9889
+ "valueType": "enum",
9890
+ "enumValues": [
9891
+ "normal",
9892
+ "offline",
9893
+ "on_batteries"
9894
+ ]
9895
+ },
9896
+ {
9897
+ "path": "error",
9898
+ "valueType": "string"
9899
+ },
9900
+ {
9901
+ "path": "errorCode",
9902
+ "valueType": "number"
9903
+ },
9904
+ {
9905
+ "path": "isDualHopper",
9906
+ "valueType": "boolean"
9907
+ },
9908
+ {
9909
+ "path": "childLock",
9910
+ "valueType": "boolean"
9911
+ },
9912
+ {
9913
+ "path": "indicatorLight",
9914
+ "valueType": "boolean"
9915
+ },
9916
+ {
9917
+ "path": "feedSound",
9918
+ "valueType": "boolean"
9919
+ },
9920
+ {
9921
+ "path": "volume",
9922
+ "valueType": "number"
9923
+ }
9924
+ ],
9925
+ "power-meter": [
9926
+ {
9927
+ "path": "watts",
9928
+ "valueType": "number"
9929
+ },
9930
+ {
9931
+ "path": "kwhTotal",
9932
+ "valueType": "number"
9933
+ },
9934
+ {
9935
+ "path": "volts",
9936
+ "valueType": "number"
9937
+ },
9938
+ {
9939
+ "path": "amps",
9940
+ "valueType": "number"
9941
+ },
9942
+ {
9943
+ "path": "va",
9944
+ "valueType": "number"
9945
+ },
9946
+ {
9947
+ "path": "powerFactor",
9948
+ "valueType": "number"
9949
+ },
9950
+ {
9951
+ "path": "unit",
9952
+ "valueType": "string"
9953
+ },
9954
+ {
9955
+ "path": "precision",
9956
+ "valueType": "number"
9957
+ }
9958
+ ],
9959
+ "presence": [
9960
+ {
9961
+ "path": "state",
9962
+ "valueType": "string"
9963
+ },
9964
+ {
9965
+ "path": "location",
9966
+ "valueType": "string"
9967
+ },
9968
+ {
9969
+ "path": "gps.latitude",
9970
+ "valueType": "number"
9971
+ },
9972
+ {
9973
+ "path": "gps.longitude",
9974
+ "valueType": "number"
9975
+ },
9976
+ {
9977
+ "path": "gps.accuracyMeters",
9978
+ "valueType": "number"
9979
+ },
9980
+ {
9981
+ "path": "batteryPercent",
9982
+ "valueType": "number"
9983
+ }
9984
+ ],
9985
+ "pressure-sensor": [
9986
+ {
9987
+ "path": "hpa",
9988
+ "valueType": "number"
9989
+ },
9990
+ {
9991
+ "path": "unit",
9992
+ "valueType": "string"
9993
+ },
9994
+ {
9995
+ "path": "precision",
9996
+ "valueType": "number"
9997
+ }
9998
+ ],
9999
+ "privacy-mask": [{
10000
+ "path": "enabled",
10001
+ "valueType": "boolean"
10002
+ }, {
10003
+ "path": "audioEnabled",
10004
+ "valueType": "boolean"
10005
+ }],
10006
+ "ptz": [
10007
+ {
10008
+ "path": "pan",
10009
+ "valueType": "number"
10010
+ },
10011
+ {
10012
+ "path": "tilt",
10013
+ "valueType": "number"
10014
+ },
10015
+ {
10016
+ "path": "zoom",
10017
+ "valueType": "number"
10018
+ },
10019
+ {
10020
+ "path": "autofocus",
10021
+ "valueType": "boolean"
10022
+ }
10023
+ ],
10024
+ "ptz-autotrack": [
10025
+ {
10026
+ "path": "enabled",
10027
+ "valueType": "boolean"
10028
+ },
10029
+ {
10030
+ "path": "currentSettings.targetType",
10031
+ "valueType": "string"
10032
+ },
10033
+ {
10034
+ "path": "currentSettings.stopDelaySeconds",
10035
+ "valueType": "number"
10036
+ },
10037
+ {
10038
+ "path": "currentSettings.disappearDelaySeconds",
10039
+ "valueType": "number"
10040
+ }
10041
+ ],
10042
+ "recording-archive": [
10043
+ {
10044
+ "path": "deviceId",
10045
+ "valueType": "number"
10046
+ },
10047
+ {
10048
+ "path": "enabled",
10049
+ "valueType": "boolean"
10050
+ },
10051
+ {
10052
+ "path": "activeMode",
10053
+ "valueType": "enum",
10054
+ "enumValues": [
10055
+ "off",
10056
+ "events",
10057
+ "continuous",
10058
+ "on-device-decision"
10059
+ ]
10060
+ },
10061
+ {
10062
+ "path": "nodeId",
10063
+ "valueType": "string"
10064
+ },
10065
+ {
10066
+ "path": "storageBytes",
10067
+ "valueType": "number"
10068
+ }
10069
+ ],
10070
+ "recording-onboard": [
10071
+ {
10072
+ "path": "primaryTrackId",
10073
+ "valueType": "string"
10074
+ },
10075
+ {
10076
+ "path": "enabled",
10077
+ "valueType": "boolean"
10078
+ },
10079
+ {
10080
+ "path": "overwriteWhenFull",
10081
+ "valueType": "boolean"
10082
+ },
10083
+ {
10084
+ "path": "preRecordSec",
10085
+ "valueType": "number"
10086
+ },
10087
+ {
10088
+ "path": "postRecordSec",
10089
+ "valueType": "number"
10090
+ },
10091
+ {
10092
+ "path": "segmentMinutes",
10093
+ "valueType": "number"
10094
+ },
10095
+ {
10096
+ "path": "unreadableWindows",
10097
+ "valueType": "number"
10098
+ },
10099
+ {
10100
+ "path": "recordingToNowhere",
10101
+ "valueType": "boolean"
10102
+ }
10103
+ ],
10104
+ "recording-signal": [{
10105
+ "path": "active",
10106
+ "valueType": "boolean"
10107
+ }, {
10108
+ "path": "reason",
10109
+ "valueType": "string"
10110
+ }],
10111
+ "running-state": [
10112
+ {
10113
+ "path": "running",
10114
+ "valueType": "boolean"
10115
+ },
10116
+ {
10117
+ "path": "since",
10118
+ "valueType": "number"
10119
+ },
10120
+ {
10121
+ "path": "source",
10122
+ "valueType": "enum",
10123
+ "enumValues": ["native", "assigned"]
10124
+ },
10125
+ {
10126
+ "path": "phase",
10127
+ "valueType": "string"
10128
+ }
10129
+ ],
10130
+ "script-runner": [
10131
+ {
10132
+ "path": "isRunning",
10133
+ "valueType": "boolean"
10134
+ },
10135
+ {
10136
+ "path": "lastRunAt",
10137
+ "valueType": "number"
10138
+ },
10139
+ {
10140
+ "path": "lastRunSuccess",
10141
+ "valueType": "boolean"
10142
+ },
10143
+ {
10144
+ "path": "lastError",
10145
+ "valueType": "string"
10146
+ }
10147
+ ],
10148
+ "smoke": [{
10149
+ "path": "detected",
10150
+ "valueType": "boolean"
10151
+ }],
10152
+ "snapshot": [
10153
+ {
10154
+ "path": "lastCapturedAt",
10155
+ "valueType": "number"
10156
+ },
10157
+ {
10158
+ "path": "cacheAgeMs",
10159
+ "valueType": "number"
10160
+ },
10161
+ {
10162
+ "path": "lastBytes",
10163
+ "valueType": "number"
10164
+ },
10165
+ {
10166
+ "path": "lastStreamId",
10167
+ "valueType": "string"
10168
+ }
10169
+ ],
10170
+ "stream-params": [
10171
+ {
10172
+ "path": "main.width",
10173
+ "valueType": "number"
10174
+ },
10175
+ {
10176
+ "path": "main.height",
10177
+ "valueType": "number"
10178
+ },
10179
+ {
10180
+ "path": "main.codec",
10181
+ "valueType": "enum",
10182
+ "enumValues": ["h264", "h265"]
10183
+ },
10184
+ {
10185
+ "path": "main.framerate",
10186
+ "valueType": "number"
10187
+ },
10188
+ {
10189
+ "path": "main.bitrate",
10190
+ "valueType": "number"
10191
+ },
10192
+ {
10193
+ "path": "main.bitrateMode",
10194
+ "valueType": "enum",
10195
+ "enumValues": ["vbr", "cbr"]
10196
+ },
10197
+ {
10198
+ "path": "main.encoderProfile",
10199
+ "valueType": "enum",
10200
+ "enumValues": [
10201
+ "high",
10202
+ "main",
10203
+ "baseline"
10204
+ ]
10205
+ },
10206
+ {
10207
+ "path": "main.gop",
10208
+ "valueType": "number"
10209
+ },
10210
+ {
10211
+ "path": "main.audio",
10212
+ "valueType": "boolean"
10213
+ },
10214
+ {
10215
+ "path": "sub.width",
10216
+ "valueType": "number"
10217
+ },
10218
+ {
10219
+ "path": "sub.height",
10220
+ "valueType": "number"
10221
+ },
10222
+ {
10223
+ "path": "sub.codec",
10224
+ "valueType": "enum",
10225
+ "enumValues": ["h264", "h265"]
10226
+ },
10227
+ {
10228
+ "path": "sub.framerate",
10229
+ "valueType": "number"
10230
+ },
10231
+ {
10232
+ "path": "sub.bitrate",
10233
+ "valueType": "number"
10234
+ },
10235
+ {
10236
+ "path": "sub.bitrateMode",
10237
+ "valueType": "enum",
10238
+ "enumValues": ["vbr", "cbr"]
10239
+ },
10240
+ {
10241
+ "path": "sub.encoderProfile",
10242
+ "valueType": "enum",
10243
+ "enumValues": [
10244
+ "high",
10245
+ "main",
10246
+ "baseline"
10247
+ ]
10248
+ },
10249
+ {
10250
+ "path": "sub.gop",
10251
+ "valueType": "number"
10252
+ },
10253
+ {
10254
+ "path": "sub.audio",
10255
+ "valueType": "boolean"
10256
+ },
10257
+ {
10258
+ "path": "ext.width",
10259
+ "valueType": "number"
10260
+ },
10261
+ {
10262
+ "path": "ext.height",
10263
+ "valueType": "number"
10264
+ },
10265
+ {
10266
+ "path": "ext.codec",
10267
+ "valueType": "enum",
10268
+ "enumValues": ["h264", "h265"]
10269
+ },
10270
+ {
10271
+ "path": "ext.framerate",
10272
+ "valueType": "number"
10273
+ },
10274
+ {
10275
+ "path": "ext.bitrate",
10276
+ "valueType": "number"
10277
+ },
10278
+ {
10279
+ "path": "ext.bitrateMode",
10280
+ "valueType": "enum",
10281
+ "enumValues": ["vbr", "cbr"]
10282
+ },
10283
+ {
10284
+ "path": "ext.encoderProfile",
10285
+ "valueType": "enum",
10286
+ "enumValues": [
10287
+ "high",
10288
+ "main",
10289
+ "baseline"
10290
+ ]
10291
+ },
10292
+ {
10293
+ "path": "ext.gop",
10294
+ "valueType": "number"
10295
+ },
10296
+ {
10297
+ "path": "ext.audio",
10298
+ "valueType": "boolean"
10299
+ }
10300
+ ],
10301
+ "switch": [{
10302
+ "path": "on",
10303
+ "valueType": "boolean"
10304
+ }],
10305
+ "tamper": [{
10306
+ "path": "tampered",
10307
+ "valueType": "boolean"
10308
+ }],
10309
+ "temperature-sensor": [
10310
+ {
10311
+ "path": "celsius",
10312
+ "valueType": "number"
10313
+ },
10314
+ {
10315
+ "path": "unit",
10316
+ "valueType": "string"
10317
+ },
10318
+ {
10319
+ "path": "precision",
10320
+ "valueType": "number"
10321
+ }
10322
+ ],
10323
+ "update": [
10324
+ {
10325
+ "path": "currentVersion",
10326
+ "valueType": "string"
10327
+ },
10328
+ {
10329
+ "path": "availableVersion",
10330
+ "valueType": "string"
10331
+ },
10332
+ {
10333
+ "path": "updatable",
10334
+ "valueType": "boolean"
10335
+ },
10336
+ {
10337
+ "path": "state",
10338
+ "valueType": "string"
10339
+ },
10340
+ {
10341
+ "path": "inProgress",
10342
+ "valueType": "boolean"
10343
+ }
10344
+ ],
10345
+ "vacuum-control": [
10346
+ {
10347
+ "path": "state",
10348
+ "valueType": "enum",
10349
+ "enumValues": [
10350
+ "idle",
10351
+ "cleaning",
10352
+ "paused",
10353
+ "returning",
10354
+ "docked",
10355
+ "drying",
10356
+ "error"
10357
+ ]
10358
+ },
10359
+ {
10360
+ "path": "batteryLevel",
10361
+ "valueType": "number"
10362
+ },
10363
+ {
10364
+ "path": "fanSpeed",
10365
+ "valueType": "string"
10366
+ },
10367
+ {
10368
+ "path": "progressPercent",
10369
+ "valueType": "number"
10370
+ },
10371
+ {
10372
+ "path": "errorCode",
10373
+ "valueType": "number"
10374
+ },
10375
+ {
10376
+ "path": "errorLabel",
10377
+ "valueType": "string"
10378
+ }
10379
+ ],
10380
+ "valve": [{
10381
+ "path": "state",
10382
+ "valueType": "enum",
10383
+ "enumValues": [
10384
+ "open",
10385
+ "opening",
10386
+ "closing",
10387
+ "closed",
10388
+ "stopped"
10389
+ ]
10390
+ }, {
10391
+ "path": "position",
10392
+ "valueType": "number"
10393
+ }],
10394
+ "vibration": [{
10395
+ "path": "detected",
10396
+ "valueType": "boolean"
10397
+ }],
10398
+ "water-heater": [
10399
+ {
10400
+ "path": "currentTemp",
10401
+ "valueType": "number"
10402
+ },
10403
+ {
10404
+ "path": "targetTemp",
10405
+ "valueType": "number"
10406
+ },
10407
+ {
10408
+ "path": "operationMode",
10409
+ "valueType": "string"
10410
+ },
10411
+ {
10412
+ "path": "away",
10413
+ "valueType": "boolean"
10414
+ },
10415
+ {
10416
+ "path": "minTemp",
10417
+ "valueType": "number"
10418
+ },
10419
+ {
10420
+ "path": "maxTemp",
10421
+ "valueType": "number"
10422
+ }
10423
+ ],
10424
+ "weather": [
10425
+ {
10426
+ "path": "condition",
10427
+ "valueType": "string"
10428
+ },
10429
+ {
10430
+ "path": "temperature",
10431
+ "valueType": "number"
10432
+ },
10433
+ {
10434
+ "path": "temperatureUnit",
10435
+ "valueType": "string"
10436
+ },
10437
+ {
10438
+ "path": "humidity",
10439
+ "valueType": "number"
10440
+ },
10441
+ {
10442
+ "path": "pressure",
10443
+ "valueType": "number"
10444
+ },
10445
+ {
10446
+ "path": "pressureUnit",
10447
+ "valueType": "string"
10448
+ },
10449
+ {
10450
+ "path": "windSpeed",
10451
+ "valueType": "number"
10452
+ },
10453
+ {
10454
+ "path": "windSpeedUnit",
10455
+ "valueType": "string"
10456
+ },
10457
+ {
10458
+ "path": "windBearing",
10459
+ "valueType": "number"
10460
+ }
10461
+ ],
10462
+ "zone-analytics": [
10463
+ {
10464
+ "path": "ts",
10465
+ "valueType": "number"
10466
+ },
10467
+ {
10468
+ "path": "frameWidth",
10469
+ "valueType": "number"
10470
+ },
10471
+ {
10472
+ "path": "frameHeight",
10473
+ "valueType": "number"
10474
+ },
10475
+ {
10476
+ "path": "frame.totalObjects",
10477
+ "valueType": "number"
10478
+ },
10479
+ {
10480
+ "path": "frame.standingObjects",
10481
+ "valueType": "number"
10482
+ },
10483
+ {
10484
+ "path": "frame.transientObjects",
10485
+ "valueType": "number"
10486
+ },
10487
+ {
10488
+ "path": "unzoned.totalObjects",
10489
+ "valueType": "number"
10490
+ },
10491
+ {
10492
+ "path": "unzoned.standingObjects",
10493
+ "valueType": "number"
10494
+ },
10495
+ {
10496
+ "path": "unzoned.transientObjects",
10497
+ "valueType": "number"
10498
+ }
10499
+ ]
10500
+ });
8524
10501
  object({
8525
10502
  code: string().regex(/^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$/),
8526
10503
  params: record(string(), union([string(), number()])).optional()
@@ -8907,7 +10884,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
8907
10884
  return DeviceRole;
8908
10885
  }({});
8909
10886
  //#endregion
8910
- //#region ../types/dist/composition-CB6PMT9p.mjs
10887
+ //#region ../types/dist/composition-kEl9mevu.mjs
8911
10888
  /**
8912
10889
  * The ffmpeg build every CamStack node downloads, per platform and arch.
8913
10890
  *
@@ -8967,7 +10944,7 @@ portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac
8967
10944
  * ONE table for everyone who asks "is this device HIGH?": the
8968
10945
  * recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
8969
10946
  * sensor markers, the orchestrator's camera-sensors bridge and
8970
- * the sources of a composite doorbell (`doorbellFeatureSources`, D671).
10947
+ * the sources of a pulse (`compilePulseOverride`, D936).
8971
10948
  * A second copy would diverge at the first cap added, and the symptom — "the
8972
10949
  * sensor rings the doorbell but does not record" — is exactly D62.
8973
10950
  *
@@ -9208,6 +11185,20 @@ var table$1 = {
9208
11185
  apply: () => {
9209
11186
  throw new ExpressionEvalError("count: stateful evaluation context is required");
9210
11187
  }
11188
+ },
11189
+ dwell: {
11190
+ minArgs: 3,
11191
+ maxArgs: 3,
11192
+ apply: () => {
11193
+ throw new ExpressionEvalError("dwell: stateful evaluation context is required");
11194
+ }
11195
+ },
11196
+ latchedAt: {
11197
+ minArgs: 1,
11198
+ maxArgs: 1,
11199
+ apply: () => {
11200
+ throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
11201
+ }
9211
11202
  }
9212
11203
  };
9213
11204
  Object.freeze(Object.assign(Object.create(null), table$1));
@@ -10647,13 +12638,22 @@ var BirthDecisionRecordSchema = object({
10647
12638
  decidedByBirthEvidence: boolean(),
10648
12639
  /** Best class-compatible crop score, or `null` when nothing compatible was
10649
12640
  * found — deliberately not 0, which would be a measurement that never was.
10650
- * Includes a box the detector's own per-class floor refused (reason
10651
- * `below-detector-floor`, D922): that box never confirms, but it is the
10652
- * score the crop really held. */
12641
+ * Includes a box the detector's own per-class floor refused (D922): since
12642
+ * D925 the gate's bar, not that floor, decides whether it confirms. */
10653
12643
  bestScore: number().nullable(),
10654
12644
  /** The bar this candidate actually faced (the phantom-cell hook may raise it). */
10655
12645
  appliedMinConfidence: number().nullable(),
10656
12646
  /**
12647
+ * The detector the gate re-judged the birth WITH (D925): the session's own
12648
+ * root model, inference-device pool and node — never a node default. `null`
12649
+ * when the frame named no session detector or no gate ran, and on rows
12650
+ * written before D925. A `session-device-unavailable` row names the session
12651
+ * detector that could not be reached.
12652
+ */
12653
+ detectorModelId: string().nullable().default(null),
12654
+ detectorDeviceKey: string().nullable().default(null),
12655
+ detectorNodeId: string().nullable().default(null),
12656
+ /**
10657
12657
  * The track's own `firstSeen` — the candidate's first frame, which is where
10658
12658
  * the timeline starts. `null` for a suppressed birth, which has no track.
10659
12659
  */
@@ -12312,7 +14312,7 @@ var LogChannelDescriptorSchema = object({
12312
14312
  * `true` is a PROMISE with two halves, and both must hold: the gate is
12313
14313
  * consulted with the numeric device id, AND every line the channel admits
12314
14314
  * carries `tags: { deviceId }` with that same numeric id. The second half is
12315
- * what makes `| json | deviceId="617"` work in Loki — `loki-payload.ts`
14315
+ * what makes `| json | deviceId="102"` work in Loki — `loki-payload.ts`
12316
14316
  * keeps `deviceId` out of the stream labels for cardinality, so the tag in
12317
14317
  * the body is the only way to filter.
12318
14318
  *
@@ -12857,7 +14857,7 @@ var ModelVariantGroupSchema = object({
12857
14857
  precision: _enum(["fp32", "int8"]).optional(),
12858
14858
  /**
12859
14859
  * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
12860
- * an alternate training of the same family (Scrypted `relu_test`); chip
14860
+ * an alternate training of the same family (plugin catalog `relu_test`); chip
12861
14861
  * label is "Test".
12862
14862
  */
12863
14863
  optimization: _enum(["standard", "test"]).optional(),
@@ -13109,8 +15109,8 @@ var ModelCatalogEntrySchema = object({
13109
15109
  provider: ModelProviderIdSchema.optional(),
13110
15110
  /**
13111
15111
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
13112
- * applies (Frigate / COCO public catalog). Set on a custom model whose raw
13113
- * labels already ARE the CamStack macros (Scrypted identity map).
15112
+ * applies (plus catalog / COCO public catalog). Set on a custom model whose raw
15113
+ * labels already ARE the CamStack macros (plugin catalog identity map).
13114
15114
  */
13115
15115
  classMap: DetectionCatalogClassMapSchema.optional(),
13116
15116
  /**
@@ -16079,7 +18079,7 @@ method(object({
16079
18079
  * `1` is real time and is the ONLY value that allows the copy branch —
16080
18080
  * anything else forces `libx264` over the window. That was priced
16081
18081
  * before it was chosen: a per-event burst measured at 0.23 s and 254 KB
16082
- * on a real 615 720p cut, against 922 KB for the copy it replaces. A
18082
+ * on a real 101 720p cut, against 922 KB for the copy it replaces. A
16083
18083
  * re-encode is capped at 720p (`EVENT_CLIP_ENCODE_MAX_WIDTH`), because
16084
18084
  * once the decode is forced the width stops being free.
16085
18085
  */
@@ -16605,6 +18605,7 @@ var CompositionRunStatusSchema = _enum([
16605
18605
  "starting",
16606
18606
  "running",
16607
18607
  "degraded",
18608
+ "incomplete",
16608
18609
  "failed"
16609
18610
  ]);
16610
18611
  var CompositionFieldStateKindSchema = _enum([
@@ -16654,6 +18655,13 @@ var ComposerUnreadableBlockSchema = object({
16654
18655
  /** The parse error, in the operator's words. */
16655
18656
  error: string()
16656
18657
  });
18658
+ /** A confirmed release the hub did not accept. `deviceId` is the claim's device. */
18659
+ var UnreleasedClaimSchema = object({
18660
+ deviceId: number().int(),
18661
+ capName: string(),
18662
+ owner: string(),
18663
+ error: string()
18664
+ });
16657
18665
  method(object({
16658
18666
  /** The shared Blocks integration; null until `core-blocks` has reconciled it. */
16659
18667
  integrationId: string().nullable(),
@@ -16663,7 +18671,13 @@ method(object({
16663
18671
  /** Operator restarts: rebuild these runtimes and re-resolve their sources. Stores nothing (D62). */
16664
18672
  restartBlockIds: array(string()),
16665
18673
  /** Composition rows that exist but do not parse: held, never withdrawn, reported failed. */
16666
- unreadableBlocks: array(ComposerUnreadableBlockSchema)
18674
+ unreadableBlocks: array(ComposerUnreadableBlockSchema),
18675
+ /**
18676
+ * Operator-confirmed deletions. Their claims are released on this apply,
18677
+ * before any replacement block claims. A block that merely vanished from the
18678
+ * snapshot is not listed here and still waits for two applies (D49).
18679
+ */
18680
+ retiredBlockIds: array(string()).optional()
16667
18681
  }), object({
16668
18682
  blocks: array(object({
16669
18683
  blockId: string(),
@@ -16675,7 +18689,13 @@ method(object({
16675
18689
  * integration unknown, its own rows unread or read empty once). An empty
16676
18690
  * apply the caller owes is paid off only by one the composer acted on (D49).
16677
18691
  */
16678
- acted: boolean()
18692
+ acted: boolean(),
18693
+ /**
18694
+ * Confirmed releases this apply tried and the hub did not accept. Empty when
18695
+ * every one landed (or there was nothing to hand back). Absent on a result
18696
+ * that never got that far.
18697
+ */
18698
+ unreleasedClaims: array(UnreleasedClaimSchema).optional()
16679
18699
  }), {
16680
18700
  kind: "mutation",
16681
18701
  auth: "admin"
@@ -16718,7 +18738,15 @@ Object.freeze({
16718
18738
  kind: "fixed",
16719
18739
  result: ["number", "null"]
16720
18740
  },
16721
- count: NUMBER
18741
+ count: NUMBER,
18742
+ dwell: {
18743
+ kind: "fixed",
18744
+ result: ["boolean", "null"]
18745
+ },
18746
+ latchedAt: {
18747
+ kind: "fixed",
18748
+ result: ["number", "null"]
18749
+ }
16722
18750
  });
16723
18751
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
16724
18752
  /**
@@ -16791,6 +18819,7 @@ var CoreBlockStatusSchema = _enum([
16791
18819
  "starting",
16792
18820
  "running",
16793
18821
  "degraded",
18822
+ "incomplete",
16794
18823
  "failed"
16795
18824
  ]);
16796
18825
  /** path → TypeScript source for a multi-file block. */
@@ -38938,7 +40967,7 @@ var PRIMARY_CATEGORIES = new Set(ENTRIES.map((e) => e.primaryCategory));
38938
40967
  * `locationKey` is ALWAYS {@link locationIconKey} of the label — never the
38939
40968
  * operator's casing. The registry matches labels trimmed + case-insensitively
38940
40969
  * everywhere (`addLocation`, `removeLocation`, `renameLocation`), and a
38941
- * case-only rename (`cucina` → `Cucina`) is a real edit this repo supports; a
40970
+ * case-only rename (`kitchen` → `Kitchen`) is a real edit this repo supports; a
38942
40971
  * map keyed on the displayed casing would orphan its entry on exactly that
38943
40972
  * edit. Consumers join by keying their own label through `locationIconKey`.
38944
40973
  */
@@ -38963,7 +40992,7 @@ var LocationDescriptionAssignmentSchema = object({
38963
40992
  /**
38964
40993
  * A SITE ZONE — a named part of the property that several locations belong to.
38965
40994
  *
38966
- * "Zona notte" holds every bedroom; "Zona giorno" the living room and the
40995
+ * "Night zone" holds every bedroom; "Zona giorno" the living room and the
38967
40996
  * kitchen. A camera belongs to exactly one location, and a location to at most
38968
40997
  * one zone, so a camera's zone is derived and never stored on the device: the
38969
40998
  * whole point of this entity is that grouping rooms touches no device row.
@@ -38992,7 +41021,7 @@ var LocationDescriptionAssignmentSchema = object({
38992
41021
  * the locations inside it.
38993
41022
  *
38994
41023
  * The LABEL is carried alongside the key because the key is lossy on purpose —
38995
- * a surface must show "Zona notte", not "zona notte". Locations are carried
41024
+ * a surface must show "Night zone", not "night zone". Locations are carried
38996
41025
  * here, rather than left to a second call, because every consumer wants both
38997
41026
  * at once and a viewer that asked twice could render a zone whose membership
38998
41027
  * it has not fetched yet.
@@ -41205,8 +43234,8 @@ var LoadContributionSchema = object({
41205
43234
  "unattributable"
41206
43235
  ]),
41207
43236
  /**
41208
- * What ONE entry is, in the contributor's own words — `615/high`,
41209
- * `617/native`, `cuda:0 shared pool`. Free text because the unit differs per
43237
+ * What ONE entry is, in the contributor's own words — `101/high`,
43238
+ * `102/native`, `cuda:0 shared pool`. Free text because the unit differs per
41210
43239
  * family and inventing a common one would lose the only information that
41211
43240
  * makes two entries for the same camera distinguishable.
41212
43241
  */
@@ -42875,6 +44904,381 @@ var _macroLookup = /* @__PURE__ */ new Map();
42875
44904
  for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
42876
44905
  for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
42877
44906
  /**
44907
+ * Palette entry ids (D939). Audio is the one gradient; `audio-*` leaves are
44908
+ * not entries. `heatmapScrub` is a mark, not an event kind.
44909
+ */
44910
+ var PALETTE_ENTRY_IDS = [
44911
+ "motion",
44912
+ "audio",
44913
+ "recording",
44914
+ "live",
44915
+ "heatmapScrub",
44916
+ "person",
44917
+ "vehicle",
44918
+ "animal",
44919
+ "package",
44920
+ "sensor",
44921
+ "control",
44922
+ "face",
44923
+ "plate",
44924
+ "car",
44925
+ "truck",
44926
+ "bus",
44927
+ "motorcycle",
44928
+ "bicycle",
44929
+ "airplane",
44930
+ "boat",
44931
+ "train",
44932
+ "bird",
44933
+ "dog",
44934
+ "cat",
44935
+ "horse",
44936
+ "sheep",
44937
+ "cow",
44938
+ "elephant",
44939
+ "bear",
44940
+ "zebra",
44941
+ "giraffe",
44942
+ "package-delivered",
44943
+ "package-picked-up",
44944
+ "suitcase",
44945
+ "backpack",
44946
+ "handbag",
44947
+ "contact",
44948
+ "motion-sensor",
44949
+ "smoke",
44950
+ "flood",
44951
+ "gas",
44952
+ "carbon-monoxide",
44953
+ "vibration",
44954
+ "tamper",
44955
+ "presence",
44956
+ "enum-sensor",
44957
+ "device-event",
44958
+ "lock",
44959
+ "cover",
44960
+ "switch",
44961
+ "siren",
44962
+ "button",
44963
+ "doorbell"
44964
+ ];
44965
+ var AUDIO_ENTRY_ID = "audio";
44966
+ /** Six rungs, quiet → loud. The opaque end is the entry's hex. */
44967
+ var AUDIO_GRADIENT_ALPHAS = [
44968
+ .3,
44969
+ .42,
44970
+ .55,
44971
+ .7,
44972
+ .85,
44973
+ 1
44974
+ ];
44975
+ var PALETTE_PRESET_IDS = [
44976
+ "camstack",
44977
+ "high-contrast",
44978
+ "okabe-ito"
44979
+ ];
44980
+ /** Frozen palette tables (D939). The spec refuses a table that breaks the rule. */
44981
+ var CAMSTACK_HEX = {
44982
+ motion: "#d946ef",
44983
+ audio: "#059eb8",
44984
+ recording: "#ef4444",
44985
+ live: "#8d7a00",
44986
+ heatmapScrub: "#4b32ff",
44987
+ person: "#11a64c",
44988
+ vehicle: "#3b82f6",
44989
+ animal: "#ea6a09",
44990
+ package: "#924667",
44991
+ sensor: "#624bbc",
44992
+ control: "#944d24",
44993
+ face: "#ed4f8d",
44994
+ plate: "#4b7027",
44995
+ car: "#9684cf",
44996
+ truck: "#0f9b89",
44997
+ bus: "#a734a9",
44998
+ motorcycle: "#c1133a",
44999
+ bicycle: "#0e6a9b",
45000
+ airplane: "#7c9928",
45001
+ boat: "#b17933",
45002
+ train: "#ad6ca3",
45003
+ bird: "#0f7c55",
45004
+ dog: "#c82700",
45005
+ cat: "#7268f2",
45006
+ horse: "#cb795e",
45007
+ sheep: "#b8636b",
45008
+ cow: "#cb2969",
45009
+ elephant: "#1158d2",
45010
+ bear: "#8d5e00",
45011
+ zebra: "#0097d6",
45012
+ giraffe: "#8f61bb",
45013
+ "package-delivered": "#cd3f9b",
45014
+ "package-picked-up": "#388a08",
45015
+ suitcase: "#666800",
45016
+ backpack: "#ec5022",
45017
+ handbag: "#a76ef8",
45018
+ contact: "#ab5a49",
45019
+ "motion-sensor": "#b95d1a",
45020
+ smoke: "#dd3858",
45021
+ flood: "#b31e7d",
45022
+ gas: "#5b70b5",
45023
+ "carbon-monoxide": "#7b4e8e",
45024
+ vibration: "#e65bba",
45025
+ tamper: "#98464b",
45026
+ presence: "#3a9468",
45027
+ "enum-sensor": "#7885f8",
45028
+ "device-event": "#8c43c8",
45029
+ lock: "#649653",
45030
+ cover: "#c67597",
45031
+ switch: "#7a812a",
45032
+ siren: "#ac5d7f",
45033
+ button: "#b276cd",
45034
+ doorbell: "#0087ab"
45035
+ };
45036
+ var CAMSTACK_FALLBACK = [
45037
+ "#b34dc7",
45038
+ "#1d7d34",
45039
+ "#db6b6c",
45040
+ "#a43d29",
45041
+ "#0e6ee6",
45042
+ "#29a10b",
45043
+ "#a98731",
45044
+ "#0181c6"
45045
+ ];
45046
+ var HIGH_CONTRAST_HEX = {
45047
+ motion: "#964360",
45048
+ audio: "#23a132",
45049
+ recording: "#2494ca",
45050
+ live: "#bd7e2b",
45051
+ heatmapScrub: "#ad6eea",
45052
+ person: "#62611e",
45053
+ vehicle: "#f4534c",
45054
+ animal: "#1556cd",
45055
+ package: "#9c4415",
45056
+ sensor: "#066c48",
45057
+ control: "#f2479f",
45058
+ face: "#139d8a",
45059
+ plate: "#909024",
45060
+ car: "#8e35ab",
45061
+ truck: "#bd0b2b",
45062
+ bus: "#7a88ca",
45063
+ motorcycle: "#e26725",
45064
+ bicycle: "#a6679b",
45065
+ airplane: "#7c5720",
45066
+ boat: "#467a1b",
45067
+ train: "#6f65a4",
45068
+ bird: "#cb717f",
45069
+ dog: "#c62490",
45070
+ cat: "#b36850",
45071
+ horse: "#1872ac",
45072
+ sheep: "#927939",
45073
+ cow: "#428a5c",
45074
+ elephant: "#d41160",
45075
+ bear: "#799453",
45076
+ zebra: "#a85455",
45077
+ giraffe: "#746be8",
45078
+ "package-delivered": "#824a80",
45079
+ "package-picked-up": "#614ac1",
45080
+ suitcase: "#2f77f3",
45081
+ backpack: "#fa476d",
45082
+ handbag: "#c14cbe",
45083
+ contact: "#c83921",
45084
+ "motion-sensor": "#a07ebd",
45085
+ smoke: "#a25b13",
45086
+ flood: "#526bab",
45087
+ gas: "#924938",
45088
+ "carbon-monoxide": "#bb7e53",
45089
+ vibration: "#b66182",
45090
+ tamper: "#3c6931",
45091
+ presence: "#6c851d",
45092
+ "enum-sensor": "#ad2d48",
45093
+ "device-event": "#5e9b04",
45094
+ lock: "#00a062",
45095
+ cover: "#ad8624",
45096
+ switch: "#d05259",
45097
+ siren: "#cd67b3",
45098
+ button: "#c9746a",
45099
+ doorbell: "#338eeb"
45100
+ };
45101
+ var HIGH_CONTRAST_FALLBACK = [
45102
+ "#817f3b",
45103
+ "#a0733e",
45104
+ "#8658b2",
45105
+ "#956301",
45106
+ "#bc652d",
45107
+ "#647331",
45108
+ "#a14c9e",
45109
+ "#d14e71"
45110
+ ];
45111
+ var OKABE_ITO_HEX = {
45112
+ motion: "#b88128",
45113
+ audio: "#1096c8",
45114
+ recording: "#009e73",
45115
+ live: "#9c8c22",
45116
+ heatmapScrub: "#0072b2",
45117
+ person: "#d55e00",
45118
+ vehicle: "#c0739f",
45119
+ animal: "#226d18",
45120
+ package: "#91446c",
45121
+ sensor: "#217b56",
45122
+ control: "#648647",
45123
+ face: "#c22998",
45124
+ plate: "#fa4575",
45125
+ car: "#956301",
45126
+ truck: "#2f77f3",
45127
+ bus: "#7a4e86",
45128
+ motorcycle: "#f54597",
45129
+ bicycle: "#bb3e75",
45130
+ airplane: "#e054c0",
45131
+ boat: "#457942",
45132
+ train: "#867afa",
45133
+ bird: "#88914c",
45134
+ dog: "#1556cd",
45135
+ cat: "#71702c",
45136
+ horse: "#9b4fa4",
45137
+ sheep: "#c0559d",
45138
+ cow: "#d14f65",
45139
+ elephant: "#98470f",
45140
+ bear: "#595896",
45141
+ zebra: "#96790e",
45142
+ giraffe: "#cb717b",
45143
+ "package-delivered": "#139d8a",
45144
+ "package-picked-up": "#906ead",
45145
+ suitcase: "#d02939",
45146
+ backpack: "#d41160",
45147
+ handbag: "#f64f54",
45148
+ contact: "#7258d2",
45149
+ "motion-sensor": "#b66182",
45150
+ smoke: "#627abb",
45151
+ flood: "#b86ae4",
45152
+ gas: "#a95261",
45153
+ "carbon-monoxide": "#c65d3c",
45154
+ vibration: "#7a40b7",
45155
+ tamper: "#914b34",
45156
+ presence: "#9481c3",
45157
+ "enum-sensor": "#ac6d47",
45158
+ "device-event": "#7b6fce",
45159
+ lock: "#c67662",
45160
+ cover: "#a6564d",
45161
+ switch: "#ad2c4e",
45162
+ siren: "#348e08",
45163
+ button: "#d27303",
45164
+ doorbell: "#55770f"
45165
+ };
45166
+ var OKABE_ITO_FALLBACK = [
45167
+ "#9a3784",
45168
+ "#a7392c",
45169
+ "#409d50",
45170
+ "#6987e7",
45171
+ "#ee5b3d",
45172
+ "#c0430d",
45173
+ "#af79b3",
45174
+ "#4b6628"
45175
+ ];
45176
+ /**
45177
+ * The display palette (D939). One table of colours, three presets, one
45178
+ * validator. Taxonomy colours and every consumer read this — there is no
45179
+ * second hex table.
45180
+ */
45181
+ var paletteHexSchema = string().regex(/^#[0-9a-f]{6}$/);
45182
+ var paletteSwatchSchema = discriminatedUnion("form", [object({
45183
+ form: literal("solid"),
45184
+ hex: paletteHexSchema
45185
+ }), object({
45186
+ form: literal("gradient"),
45187
+ hex: paletteHexSchema,
45188
+ alphas: array(number().gt(0).lte(1)).length(AUDIO_GRADIENT_ALPHAS.length)
45189
+ })]);
45190
+ var paletteReadySchema = object({
45191
+ status: literal("ready"),
45192
+ presetId: _enum(PALETTE_PRESET_IDS),
45193
+ customized: boolean(),
45194
+ source: _enum(["stored", "unconfigured"]),
45195
+ swatches: record(string(), paletteSwatchSchema),
45196
+ fallbacks: array(paletteHexSchema).length(8)
45197
+ });
45198
+ var paletteResultSchema = discriminatedUnion("status", [paletteReadySchema, object({
45199
+ status: literal("unknown"),
45200
+ reason: string()
45201
+ })]);
45202
+ var setPaletteInputSchema = union([object({ presetId: string() }), object({
45203
+ presetId: string(),
45204
+ overrides: record(string(), paletteSwatchSchema)
45205
+ })]);
45206
+ object({
45207
+ presetId: string(),
45208
+ overrides: record(string(), paletteSwatchSchema)
45209
+ });
45210
+ function solid(hex) {
45211
+ return {
45212
+ form: "solid",
45213
+ hex
45214
+ };
45215
+ }
45216
+ function audioGradient(hex) {
45217
+ return {
45218
+ form: "gradient",
45219
+ hex,
45220
+ alphas: [...AUDIO_GRADIENT_ALPHAS]
45221
+ };
45222
+ }
45223
+ function swatchesFrom(hexes) {
45224
+ const out = {};
45225
+ for (const id of PALETTE_ENTRY_IDS) {
45226
+ const hex = hexes[id];
45227
+ if (hex === void 0) throw new Error(`palette table missing ${id}`);
45228
+ out[id] = id === "audio" ? audioGradient(hex) : solid(hex);
45229
+ }
45230
+ return out;
45231
+ }
45232
+ function preset(id, name, hexes, fallbacks) {
45233
+ return {
45234
+ id,
45235
+ name,
45236
+ swatches: swatchesFrom(hexes),
45237
+ fallbacks
45238
+ };
45239
+ }
45240
+ var DISPLAY_PRESETS = [
45241
+ preset("camstack", "CamStack", CAMSTACK_HEX, CAMSTACK_FALLBACK),
45242
+ preset("high-contrast", "High contrast", HIGH_CONTRAST_HEX, HIGH_CONTRAST_FALLBACK),
45243
+ preset("okabe-ito", "Colour-blind safe", OKABE_ITO_HEX, OKABE_ITO_FALLBACK)
45244
+ ];
45245
+ function presetById(id) {
45246
+ return DISPLAY_PRESETS.find((item) => item.id === id);
45247
+ }
45248
+ function bundledCamstack() {
45249
+ const presetRow = presetById("camstack");
45250
+ if (presetRow === void 0) throw new Error("CamStack preset missing");
45251
+ return readyOf(presetRow, "unconfigured", false);
45252
+ }
45253
+ function readyOf(row, source, customized) {
45254
+ return {
45255
+ status: "ready",
45256
+ presetId: row.id,
45257
+ customized,
45258
+ source,
45259
+ swatches: row.swatches,
45260
+ fallbacks: [...row.fallbacks]
45261
+ };
45262
+ }
45263
+ function hashFallback(kind, fallbacks) {
45264
+ let hash = 0;
45265
+ for (let i = 0; i < kind.length; i++) hash = hash * 31 + (kind.codePointAt(i) ?? 0) >>> 0;
45266
+ const hex = fallbacks[hash % fallbacks.length];
45267
+ if (hex === void 0) throw new Error("display palette has no fallback colour");
45268
+ return hex;
45269
+ }
45270
+ /** Colour a kind paints with. Audio leaves share the audio gradient's hex. */
45271
+ function paintHex(swatches, fallbacks, kind) {
45272
+ const key = kind.trim().toLowerCase();
45273
+ if (key.startsWith("audio-")) {
45274
+ const audio = swatches[AUDIO_ENTRY_ID];
45275
+ return audio !== void 0 ? audio.hex : hashFallback(key, fallbacks);
45276
+ }
45277
+ const direct = swatches[key];
45278
+ if (direct !== void 0) return direct.hex;
45279
+ return hashFallback(key, fallbacks);
45280
+ }
45281
+ /**
42878
45282
  * Unified event-kind taxonomy — THE single source of truth for
42879
45283
  * `kind → { parentKind, category, level, color, iconId, labelKey, label,
42880
45284
  * icon }`.
@@ -42888,109 +45292,88 @@ for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set
42888
45292
  * - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
42889
45293
  * - the COCO / audio class maps (macro ↔ sub relationships)
42890
45294
  *
42891
- * The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
42892
- * `@camstack/types`. The UI-side mapping `iconId → lucide component` and
42893
- * `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
42894
- * color or an icon: they read this dictionary (server descriptors carry the
42895
- * fields inline; the client resolves color/icon/label from `iconId`/`kind`).
45295
+ * The DATA (serializable — parentKind / iconId / labelKey) lives here in
45296
+ * `@camstack/types`. Colour is NOT a second table: each entry's `color` is
45297
+ * the bundled CamStack display palette (D939). The effective cluster palette
45298
+ * is the `display-palette` capability. The UI-side mapping `iconId → lucide
45299
+ * component` and `labelKey → t()` lives in `@camstack/ui-library`.
42896
45300
  *
42897
45301
  * Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
42898
45302
  */
42899
- var TAXONOMY_COLORS = {
42900
- motion: "#f59e0b",
42901
- audio: "#06b6d4",
42902
- person: "#22c55e",
42903
- vehicle: "#3b82f6",
42904
- animal: "#f97316",
42905
- package: "#a855f7",
42906
- sensor: "#8b5cf6",
42907
- control: "#10b981",
42908
- genericDetection: "#64748b"
42909
- };
42910
- var DETECTION_SUB_COLORS = {
42911
- car: "#f59e0b",
42912
- truck: "#d97706",
42913
- bus: "#b45309",
42914
- motorcycle: "#eab308",
42915
- bicycle: "#ca8a04",
42916
- airplane: "#60a5fa",
42917
- boat: "#2563eb",
42918
- train: "#1d4ed8",
42919
- bird: "#14b8a6",
42920
- dog: "#84cc16",
42921
- cat: "#f97316",
42922
- horse: "#a16207",
42923
- sheep: "#a3a3a3",
42924
- cow: "#78716c",
42925
- elephant: "#6b7280",
42926
- bear: "#7c2d12",
42927
- zebra: "#404040",
42928
- giraffe: "#d4a373"
42929
- };
45303
+ var BUNDLED_PALETTE = bundledCamstack();
45304
+ function kindColor(kind) {
45305
+ return paintHex(BUNDLED_PALETTE.swatches, BUNDLED_PALETTE.fallbacks, kind);
45306
+ }
45307
+ function firstFallback(fallbacks) {
45308
+ const hex = fallbacks[0];
45309
+ if (hex === void 0) throw new Error("display palette has no fallback colour");
45310
+ return hex;
45311
+ }
45312
+ firstFallback(BUNDLED_PALETTE.fallbacks);
42930
45313
  function titleCase(id) {
42931
45314
  return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
42932
45315
  }
42933
45316
  var entries = /* @__PURE__ */ new Map();
42934
- function macro(kind, category, color, iconId, label) {
45317
+ function macro(kind, category, iconId, label) {
42935
45318
  entries.set(kind, {
42936
45319
  kind,
42937
45320
  parentKind: null,
42938
45321
  level: "macro",
42939
45322
  category,
42940
- color,
45323
+ color: kindColor(kind),
42941
45324
  iconId,
42942
45325
  labelKey: `eventKind.${kind}`,
42943
45326
  label
42944
45327
  });
42945
45328
  }
42946
- function sub(kind, parentKind, category, color, iconId, label) {
45329
+ function sub(kind, parentKind, category, iconId, label) {
42947
45330
  entries.set(kind, {
42948
45331
  kind,
42949
45332
  parentKind,
42950
45333
  level: "sub",
42951
45334
  category,
42952
- color,
45335
+ color: kindColor(kind),
42953
45336
  iconId,
42954
45337
  labelKey: `eventKind.${kind}`,
42955
45338
  label
42956
45339
  });
42957
45340
  }
42958
- macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
42959
- macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
42960
- macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
42961
- macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
42962
- macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
42963
- macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
42964
- macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
42965
- macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
45341
+ macro("motion", "motion", "motion", "Motion");
45342
+ macro("audio", "audio", "audio", "Audio");
45343
+ macro("person", "detection", "person", "Person");
45344
+ macro("vehicle", "detection", "vehicle", "Vehicle");
45345
+ macro("animal", "detection", "animal", "Animal");
45346
+ macro("package", "package", "package", "Package");
45347
+ macro("sensor", "sensor", "sensor", "Sensor");
45348
+ macro("control", "control", "control", "Control");
42966
45349
  for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
42967
45350
  if (macroClass !== "vehicle" && macroClass !== "animal") continue;
42968
45351
  if (entries.has(cocoClass)) continue;
42969
- sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
42970
- }
42971
- sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
42972
- sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
42973
- sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
42974
- sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
42975
- sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
42976
- sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
42977
- sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
42978
- sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
42979
- sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
42980
- sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
42981
- sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
42982
- sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
42983
- sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
42984
- sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
42985
- sub("cover", "control", "control", "#0ea5e9", "door", "Cover");
42986
- sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
42987
- sub("siren", "control", "control", "#dc2626", "siren", "Siren");
42988
- sub("button", "control", "control", "#10b981", "button", "Button");
42989
- sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
45352
+ sub(cocoClass, macroClass, "detection", cocoClass, titleCase(cocoClass));
45353
+ }
45354
+ sub("package-delivered", "package", "package", "package", "Package delivered");
45355
+ sub("package-picked-up", "package", "package", "package", "Package picked up");
45356
+ sub("contact", "sensor", "sensor", "door", "Contact");
45357
+ sub("motion-sensor", "sensor", "sensor", "pir", "Motion sensor");
45358
+ sub("smoke", "sensor", "sensor", "smoke", "Smoke");
45359
+ sub("flood", "sensor", "sensor", "water", "Water leak");
45360
+ sub("gas", "sensor", "sensor", "gas", "Gas");
45361
+ sub("carbon-monoxide", "sensor", "sensor", "smoke", "Carbon monoxide");
45362
+ sub("vibration", "sensor", "sensor", "vibration", "Vibration");
45363
+ sub("tamper", "sensor", "sensor", "tamper", "Tamper");
45364
+ sub("presence", "sensor", "sensor", "presence", "Presence");
45365
+ sub("enum-sensor", "sensor", "sensor", "generic", "Sensor state");
45366
+ sub("device-event", "sensor", "sensor", "button", "Device event");
45367
+ sub("lock", "control", "control", "lock", "Lock");
45368
+ sub("cover", "control", "control", "door", "Cover");
45369
+ sub("switch", "control", "control", "switch", "Switch");
45370
+ sub("siren", "control", "control", "siren", "Siren");
45371
+ sub("button", "control", "control", "button", "Button");
45372
+ sub("doorbell", "control", "control", "doorbell", "Doorbell");
42990
45373
  for (const l of AUDIO_MACRO_LABELS) {
42991
45374
  const kind = `audio-${l.id}`;
42992
45375
  if (entries.has(kind)) continue;
42993
- sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
45376
+ sub(kind, "audio", "audio", kind, l.name);
42994
45377
  }
42995
45378
  /** The complete taxonomy dictionary, keyed by kind. */
42996
45379
  var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
@@ -43301,9 +45684,6 @@ var NcSystemEventKindSchema = _enum([
43301
45684
  "device-battery-normal",
43302
45685
  "device-consumable-low",
43303
45686
  "device-consumable-normal",
43304
- "device-tank-low",
43305
- "device-tank-full",
43306
- "device-tank-normal",
43307
45687
  "stream-online",
43308
45688
  "stream-offline",
43309
45689
  "node-online",
@@ -43350,13 +45730,14 @@ var NcSystemEventKindSchema = _enum([
43350
45730
  "camera-enabled"
43351
45731
  ]);
43352
45732
  /** The legacy tail of {@link NcSystemEventKindSchema} — see its docblock. */
43353
- var NC_LEGACY_SYSTEM_EVENT_KINDS = new Set([
45733
+ var NC_LEGACY_SYSTEM_EVENT_KINDS = [
43354
45734
  "camera-online",
43355
45735
  "camera-offline",
43356
45736
  "camera-disabled",
43357
45737
  "camera-enabled"
43358
- ]);
43359
- NcSystemEventKindSchema.options.filter((kind) => !NC_LEGACY_SYSTEM_EVENT_KINDS.has(kind));
45738
+ ];
45739
+ var NC_LEGACY_SYSTEM_EVENT_KIND_SET = new Set(NC_LEGACY_SYSTEM_EVENT_KINDS);
45740
+ NcSystemEventKindSchema.options.filter((kind) => !NC_LEGACY_SYSTEM_EVENT_KIND_SET.has(kind));
43360
45741
  /**
43361
45742
  * The panel's transitions, as ONE list.
43362
45743
  *
@@ -43879,7 +46260,7 @@ var NcConditionsSchema = object({
43879
46260
  * with the list under it is worse than no switch (D62).
43880
46261
  *
43881
46262
  * MEMBERS ARE FACE-GALLERY `Identity.id`s (uuid), not display names. A name is
43882
- * renameable, and a rule authored on "Gianluca" went silently dark the moment
46263
+ * renameable, and a rule authored on "Alice" went silently dark the moment
43883
46264
  * the operator fixed the spelling. The id reaches the record on
43884
46265
  * `LabelAttribution.identityId`; the name is what the editor shows and what
43885
46266
  * `{{label}}` renders.
@@ -44430,7 +46811,7 @@ var NcRulePatchSchema = NcRuleInputSchema.partial().extend({
44430
46811
  * A rule scoped to one camera and one zone silently became a rule that
44431
46812
  * matches EVERY event on EVERY camera, and lost its `media` policy
44432
46813
  * (zoneCrop / gif / clip / frame) and its `priority` at the same time. Seen
44433
- * live on 2026-08-12: a rule scoped to device 617 fired on 590 and 615
46814
+ * live on 2026-08-12: a rule scoped to device 102 fired on 104 and 101
44434
46815
  * within a minute of a two-field patch.
44435
46816
  *
44436
46817
  * So every defaulted field is re-declared here WITHOUT its default. The
@@ -44475,18 +46856,11 @@ var NcRuleSchema = NcRuleInputSchema.extend({
44475
46856
  */
44476
46857
  disabledTargetIds: array(string()).default([])
44477
46858
  });
44478
- /**
44479
- * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
44480
- * report a still-true state. `addons` is the crash-looped addons only and
44481
- * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
44482
- * job is not an open state, and the alarm stays instant.
44483
- */
44484
46859
  var NcStateSummarySectionIdSchema = _enum([
44485
46860
  "device-state",
44486
46861
  "streams",
44487
46862
  "battery",
44488
46863
  "consumables",
44489
- "tanks",
44490
46864
  "detection-blind",
44491
46865
  "nodes",
44492
46866
  "addons",
@@ -45787,6 +48161,18 @@ Object.freeze({
45787
48161
  reason: "camera sensor mappings not loaded"
45788
48162
  });
45789
48163
  /**
48164
+ * What the vision model must answer before a package event is emitted
48165
+ * when a packages rule has "Confirm with the LLM" on.
48166
+ *
48167
+ * `package` is the verdict. `confidence` is 0..1. `reason` is the model's
48168
+ * one-line explanation, stored on the event so a drop is not silent.
48169
+ */
48170
+ var PackageLlmVerdictSchema = object({
48171
+ package: boolean(),
48172
+ confidence: number().min(0).max(1),
48173
+ reason: string().min(1)
48174
+ });
48175
+ /**
45790
48176
  * A model choice has a SCOPE, and a scope change has a workflow.
45791
48177
  *
45792
48178
  * ## The two scopes
@@ -46238,7 +48624,7 @@ var LabelAttributionSchema = object({
46238
48624
  * `Identity.id` or a plate-gallery `Vehicle.id` (both `randomUUID`).
46239
48625
  *
46240
48626
  * The text alone is a DISPLAY NAME, and a display name is renameable: a
46241
- * notification rule authored on "Gianluca" stopped matching the moment the
48627
+ * notification rule authored on "Alice" stopped matching the moment the
46242
48628
  * operator fixed the spelling in the gallery, and nothing said so. The id is
46243
48629
  * the thing that does not move, so it is what a rule matches on
46244
48630
  * (`NcConditions.identities`) and the text is what a human is shown.
@@ -46723,6 +49109,21 @@ var ObjectEventSchema = object({
46723
49109
  * pick-up written before D684 — UNKNOWN, never 0 and never `timestamp`.
46724
49110
  */
46725
49111
  observedAt: number().optional(),
49112
+ /**
49113
+ * The delivery was emitted without a vision-model yes (D931).
49114
+ *
49115
+ * Set only when the packages rule asked for an LLM confirm and the model
49116
+ * was unreachable, timed out, or answered something that did not parse.
49117
+ * A notification reads it so it can say "possible" instead of a definite
49118
+ * delivery. Absent on every other row, and on a confirm that said yes.
49119
+ */
49120
+ packagePossible: boolean().optional(),
49121
+ /**
49122
+ * The vision model's verdict, when a packages rule asked for one and the
49123
+ * model answered the schema (D931). A "no" never becomes a row — the
49124
+ * detector drops it and logs the reason. Present on a yes.
49125
+ */
49126
+ packageLlmVerdict: PackageLlmVerdictSchema.optional(),
46726
49127
  /** The parent track's key-event importance [0,1], propagated to every object
46727
49128
  * event of the track (so an event row can be sorted by importance without a
46728
49129
  * track join). Absent on legacy rows / before the track was scored. */
@@ -48520,7 +50921,6 @@ var PipelineAddonSchemaSchema = object({
48520
50921
  defaultModelId: string(),
48521
50922
  defaultModelIdByFormat: record(string(), string()).optional(),
48522
50923
  enabledByDefault: boolean().optional(),
48523
- backfillIntoExistingOverrides: boolean().optional(),
48524
50924
  defaultConfidence: number(),
48525
50925
  group: string().optional(),
48526
50926
  configSchema: array(ConfigFieldBridge).readonly().optional()
@@ -48647,13 +51047,12 @@ var AudioTestResultSchema = object({
48647
51047
  error: string().optional(),
48648
51048
  frame: custom().optional()
48649
51049
  });
48650
- var PipelineConfigBridge = custom();
48651
51050
  var ConfigUISchemaBridge = custom();
48652
51051
  var ConfigUISchemaNullableBridge = custom();
48653
51052
  var InferenceCapabilitiesBridge = custom();
48654
51053
  var ModelAvailabilityListBridge = custom();
48655
51054
  var PipelineRunResultBridge = custom();
48656
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
51055
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
48657
51056
  modelId: string(),
48658
51057
  settings: record(string(), unknown()).readonly()
48659
51058
  }))), method(object({ steps: record(string(), object({
@@ -48662,28 +51061,6 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
48662
51061
  })) }), object({ success: literal(true) }), {
48663
51062
  kind: "mutation",
48664
51063
  auth: "admin"
48665
- }), method(object({ nodeId: string() }), object({
48666
- success: literal(true),
48667
- clearedDevices: number()
48668
- }), {
48669
- kind: "mutation",
48670
- auth: "admin"
48671
- }), method(object({
48672
- nodeId: string(),
48673
- deviceIds: array(number()).readonly().optional(),
48674
- dryRun: boolean()
48675
- }), object({
48676
- entries: array(object({
48677
- deviceId: number(),
48678
- keys: array(string()).readonly()
48679
- })).readonly(),
48680
- refused: array(object({
48681
- deviceId: number(),
48682
- reason: string()
48683
- })).readonly()
48684
- }), {
48685
- kind: "mutation",
48686
- auth: "admin"
48687
51064
  }), method(object({ nodeId: string() }), object({ unhealthy: array(object({
48688
51065
  /** `<backend>:<device>`, e.g. `openvino:gpu`. */
48689
51066
  deviceKey: string(),
@@ -48706,7 +51083,7 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
48706
51083
  }), object({ rearmed: boolean() }), {
48707
51084
  kind: "mutation",
48708
51085
  auth: "admin"
48709
- }), method(_void(), PipelineSchemaSchema), method(_void(), array(PipelineDefaultStepSchema).readonly().nullable()), method(_void(), PipelineConfigBridge), method(_void(), ConfigUISchemaBridge), method(object({
51086
+ }), method(_void(), PipelineSchemaSchema), method(_void(), ConfigUISchemaBridge), method(object({
48710
51087
  steps: array(PipelineStepInputSchema),
48711
51088
  deviceKey: string().optional()
48712
51089
  }), PipelineValidationResultSchema), method(_void(), InferenceCapabilitiesBridge), method(object({ addonId: string() }), ModelAvailabilityListBridge), method(object({
@@ -48786,7 +51163,7 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
48786
51163
  /**
48787
51164
  * Root-supplied detections for the tree's ROOT step (D730). Set by
48788
51165
  * `runDetailSubtree` when the camera's root model supplies a crop-kind
48789
- * step (a Frigate+ `license_plate` for `plate-detection`): the step is
51166
+ * step (a plus catalog `license_plate` for `plate-detection`): the step is
48790
51167
  * NOT inferred, these boxes are its output, and its children (the plate
48791
51168
  * reader) run on them through their own crop policy. Boxes are in the
48792
51169
  * PIXELS of the image this call carries. Absent ⇒ the root step runs.
@@ -48954,11 +51331,18 @@ var KeptReasonSchema = _enum(["custom-pin"]);
48954
51331
  * Where a choice's latency came from (D791): this node's own benchmark
48955
51332
  * result, or the hardware-class table. Measured on the node beats the table.
48956
51333
  */
48957
- var LatencySourceSchema = discriminatedUnion("kind", [object({ kind: literal("table") }), object({
48958
- kind: literal("node-benchmark"),
48959
- resultId: string(),
48960
- measuredAtMs: number()
48961
- })]);
51334
+ var LatencySourceSchema = discriminatedUnion("kind", [
51335
+ object({ kind: literal("table") }),
51336
+ object({
51337
+ kind: literal("node-benchmark"),
51338
+ resultId: string(),
51339
+ measuredAtMs: number()
51340
+ }),
51341
+ object({
51342
+ kind: literal("estimated"),
51343
+ estimatedFrom: HardwareClassIdSchema
51344
+ })
51345
+ ]);
48962
51346
  var DeviceModelChoiceSchema = object({
48963
51347
  modelId: string(),
48964
51348
  p50Ms: number(),
@@ -48966,6 +51350,11 @@ var DeviceModelChoiceSchema = object({
48966
51350
  measured: boolean(),
48967
51351
  /** Absent on a plan from before D791 — read as the table. */
48968
51352
  source: LatencySourceSchema.optional(),
51353
+ /**
51354
+ * The measured class this latency was scaled from (D930). Absent when the
51355
+ * cell is the table or a node benchmark.
51356
+ */
51357
+ estimatedFrom: HardwareClassIdSchema.optional(),
48969
51358
  /** Parallel sessions at the camera rate with the headroom kept free: ⌊fps × (1 − headroom) / camera fps⌋. */
48970
51359
  capacitySessions: number(),
48971
51360
  personRecall: number()
@@ -49005,40 +51394,20 @@ var NodeDeviceChangeSchema = object({
49005
51394
  keys: array(string()).readonly()
49006
51395
  })).readonly()
49007
51396
  });
49008
- var CameraOverrideClearSchema = object({
49009
- deviceId: number(),
49010
- source: _enum(["step-override", "wholesale"]),
51397
+ /**
51398
+ * Every model and model-bound threshold lives on the accelerator that runs it
51399
+ * (D927), so the plan writes node / device entries only — there is no camera
51400
+ * layer for it to clear.
51401
+ */
51402
+ var AutoTuneWarningSchema = discriminatedUnion("kind", [object({
51403
+ kind: literal("custom-pin-kept"),
49011
51404
  nodeId: string(),
49012
- deviceKey: string().nullable(),
49013
- stepId: string(),
49014
- modelIdBefore: string().nullable(),
49015
- keys: array(string()).readonly()
49016
- });
49017
- var DetectorStoreClearSchema = object({
49018
- deviceId: number(),
49019
- keys: array(string()).readonly()
49020
- });
49021
- var AutoTuneWarningSchema = discriminatedUnion("kind", [
49022
- object({
49023
- kind: literal("detector-store-cluster-wide"),
49024
- skippedNodes: array(string()).readonly()
49025
- }),
49026
- object({
49027
- kind: literal("detector-store-unreadable"),
49028
- error: string()
49029
- }),
49030
- object({
49031
- kind: literal("custom-pin-kept"),
49032
- nodeId: string(),
49033
- deviceKey: string().nullable(),
49034
- deviceId: number().nullable(),
49035
- modelId: string()
49036
- }),
49037
- object({
49038
- kind: literal("custom-registry-unreadable"),
49039
- error: string()
49040
- })
49041
- ]);
51405
+ deviceKey: string(),
51406
+ modelId: string()
51407
+ }), object({
51408
+ kind: literal("custom-registry-unreadable"),
51409
+ error: string()
51410
+ })]);
49042
51411
  var AutoTuneOptionsSchema = object({
49043
51412
  /** Share of each accelerator's throughput kept free (0.3–0.5). */
49044
51413
  headroom: number().min(.3).max(.5).default(.4),
@@ -49060,8 +51429,6 @@ var AutoTunePlanSchema = object({
49060
51429
  generatedAt: number(),
49061
51430
  nodes: array(NodeRecommendationSchema).readonly(),
49062
51431
  nodeChanges: array(NodeDeviceChangeSchema).readonly(),
49063
- cameraClears: array(CameraOverrideClearSchema).readonly(),
49064
- detectorStoreClears: array(DetectorStoreClearSchema).readonly(),
49065
51432
  warnings: array(AutoTuneWarningSchema).readonly()
49066
51433
  });
49067
51434
  var AutoTuneApplyInputSchema = object({
@@ -49072,8 +51439,6 @@ var AutoTuneApplyInputSchema = object({
49072
51439
  var AutoTunePhaseResultSchema = object({
49073
51440
  phase: _enum([
49074
51441
  "download",
49075
- "camera-overrides",
49076
- "detector-thresholds",
49077
51442
  "node-models",
49078
51443
  "redispatch"
49079
51444
  ]),
@@ -50475,7 +52840,7 @@ var RunnerCameraConfigSchema = object({
50475
52840
  * detection session that asks for history. What shipped was a last-moment
50476
52841
  * discard — `FrameSlot`'s throttle compares wall clocks, and ~4 s of media
50477
52842
  * arriving inside a few hundred ms of wall clock looks to it like one frame's
50478
- * worth. Device 617, 2026-09-08: a re-run of the SAME model over the stored
52843
+ * worth. Device 102, 2026-09-08: a re-run of the SAME model over the stored
50479
52844
  * recording scored the subject `vehicle 0.5669` — above the 0.50 floor —
50480
52845
  * 1.68 s BEFORE the live track was born, on a frame that was in the pre-roll,
50481
52846
  * was decoded, and was freed.
@@ -50828,6 +53193,12 @@ var AgentPipelineSettingsSchema = object({
50828
53193
  /** Hub-persisted UI colour (`--color-node-*` theme tokens). */
50829
53194
  color: NodeColorIdSchema.optional(),
50830
53195
  /**
53196
+ * NODE-wide step settings (D927): `stepId → { key → value }`, applied on
53197
+ * every accelerator of the node under the device's own settings. Never a
53198
+ * model or a model-bound threshold. Written by `setNodeStepSettings`.
53199
+ */
53200
+ stepSettings: record(string(), record(string(), unknown()).readonly()).optional(),
53201
+ /**
50831
53202
  * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
50832
53203
  * weight, steps}. Absent / all-disabled ⇒ the node's single default
50833
53204
  * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
@@ -50843,17 +53214,6 @@ var AgentPipelineSettingsSchema = object({
50843
53214
  steps: record(string(), DeviceStepConfigSchema).optional()
50844
53215
  })).optional()
50845
53216
  });
50846
- var CameraPipelineForAgentSchema = object({
50847
- steps: array(PipelineStepInputSchema).readonly(),
50848
- audio: object({
50849
- modelId: string(),
50850
- enabled: boolean()
50851
- }).nullable()
50852
- });
50853
- var CameraStepOverridePatchSchema = object({
50854
- modelId: string().optional(),
50855
- settings: record(string(), unknown()).readonly().optional()
50856
- });
50857
53217
  var CameraStepSettingsSchema = record(string(), record(string(), unknown()).readonly());
50858
53218
  /** The three root-detector choices a camera has (D507: at most one root). */
50859
53219
  var CameraDetectionSourceSchema = _enum([
@@ -50863,9 +53223,7 @@ var CameraDetectionSourceSchema = _enum([
50863
53223
  ]);
50864
53224
  var CameraPipelineSettingsSchema = object({
50865
53225
  stepToggles: record(string(), boolean()).optional(),
50866
- stepSettings: CameraStepSettingsSchema.optional(),
50867
- stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
50868
- pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
53226
+ stepSettings: CameraStepSettingsSchema.optional()
50869
53227
  });
50870
53228
  /**
50871
53229
  * Pipeline placement record persisted by `addon-pipeline-orchestrator` via
@@ -51411,6 +53769,13 @@ method(object({
51411
53769
  }), object({ success: literal(true) }), {
51412
53770
  kind: "mutation",
51413
53771
  auth: "admin"
53772
+ }), method(object({
53773
+ agentNodeId: string(),
53774
+ addonId: string(),
53775
+ settings: record(string(), unknown()).nullable()
53776
+ }), object({ success: literal(true) }), {
53777
+ kind: "mutation",
53778
+ auth: "admin"
51414
53779
  }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({
51415
53780
  agentNodeId: string(),
51416
53781
  deviceKey: string()
@@ -51420,9 +53785,7 @@ method(object({
51420
53785
  }), method(object({ agentNodeId: string() }), object({
51421
53786
  success: literal(true),
51422
53787
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
51423
- effectiveModelId: string().nullable(),
51424
- /** Number of cameras whose node-scoped overrides were cleared. */
51425
- clearedCameraOverrides: number()
53788
+ effectiveModelId: string().nullable()
51426
53789
  }), {
51427
53790
  kind: "mutation",
51428
53791
  auth: "admin"
@@ -51477,15 +53840,6 @@ method(object({
51477
53840
  }), object({ success: literal(true) }), {
51478
53841
  kind: "mutation",
51479
53842
  auth: "admin"
51480
- }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
51481
- deviceId: number(),
51482
- agentNodeId: string(),
51483
- deviceKey: string(),
51484
- addonId: string(),
51485
- patch: CameraStepOverridePatchSchema.nullable()
51486
- }), object({ success: literal(true) }), {
51487
- kind: "mutation",
51488
- auth: "admin"
51489
53843
  }), method(object({
51490
53844
  deviceId: number(),
51491
53845
  addonId: string(),
@@ -51493,13 +53847,6 @@ method(object({
51493
53847
  }), object({ success: literal(true) }), {
51494
53848
  kind: "mutation",
51495
53849
  auth: "admin"
51496
- }), method(object({
51497
- deviceId: number(),
51498
- agentNodeId: string(),
51499
- pipeline: CameraPipelineForAgentSchema.nullable()
51500
- }), object({ success: literal(true) }), {
51501
- kind: "mutation",
51502
- auth: "admin"
51503
53850
  }), method(object({
51504
53851
  deviceId: number(),
51505
53852
  agentNodeId: string().optional()
@@ -52627,7 +54974,7 @@ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config:
52627
54974
  * The signals a device can emit to WAKE its own stream.
52628
54975
  *
52629
54976
  * A camera whose stream is built on demand sleeps until something asks for it,
52630
- * and "something" cannot be a consumer that is merely attached — a Frigate-style
54977
+ * and "something" cannot be a consumer that is merely attached — a external-catalog
52631
54978
  * puller holds a session open for ever, and treating that as demand would keep
52632
54979
  * a battery camera awake for ever, which is the whole thing the battery is for
52633
54980
  * (D173). So the wake has to come from the CAMERA: an event it noticed by
@@ -53395,7 +55742,7 @@ var ClipSchema = object({
53395
55742
  * {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
53396
55743
  *
53397
55744
  * Bounded because it is not a payload the surface pages through: one visit on
53398
- * device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
55745
+ * device 101 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
53399
55746
  * camera-day. Read {@link eventCount} for the true total.
53400
55747
  */
53401
55748
  eventIds: array(string()).optional(),
@@ -53540,7 +55887,7 @@ var ClipPlaybackSchema = object({
53540
55887
  * camera has no recordings", which is the defect this whole line of work is
53541
55888
  * about: a battery camera nobody woke (`sleeping`), a camera that could not be
53542
55889
  * reached at all (`unreachable`, also what a provider that THREW reports), a
53543
- * camera whose SD card is not mounted (`no-storage`, measured on 640 —
55890
+ * camera whose SD card is not mounted (`no-storage`, measured on 106 —
53544
55891
  * `HddInfo mount 0`, honestly nothing to list rather than "no clips"), and a
53545
55892
  * camera whose OWN index disagrees with its OWN calendar (`index-empty`,
53546
55893
  * measured on 618: the calendar marks 3–20 September, days 6–20 list zero
@@ -54001,7 +56348,7 @@ var videoclipsCapability = {
54001
56348
  *
54002
56349
  * It was optional, documented as "absent means the device's BOUND
54003
56350
  * provider, which is CamStack on every camera". No code implemented
54004
- * that. Measured on the live hub 2026-09-20 — device 592, bound to
56351
+ * that. Measured on the live hub 2026-09-20 — device 107, bound to
54005
56352
  * `recorder` AND `provider-reolink` — a bare call with `limit: 3`
54006
56353
  * answered SIX rows, three from each source, merged newest-first:
54007
56354
  * `device-collection-dispatch.ts` simply left the fan-out un-narrowed,
@@ -55318,7 +57665,10 @@ var airQualitySensorCapability = {
55318
57665
  */
55319
57666
  var AmbientLightSensorStatusSchema = object({
55320
57667
  /** Current illuminance in lux (lx). */
55321
- lux: number().min(0),
57668
+ lux: number().min(0).meta({
57669
+ unit: "lx",
57670
+ label: "Illuminance"
57671
+ }),
55322
57672
  /** Ms epoch when the slice was last updated. */
55323
57673
  lastFetchedAt: number(),
55324
57674
  /** Live display unit from the upstream source (e.g. HA
@@ -55361,7 +57711,12 @@ var ambientLightSensorCapability = {
55361
57711
  } } },
55362
57712
  /** Clock fields: written, but excluded from the compare that decides
55363
57713
  * whether persisting is worth a SQLite commit. */
55364
- volatileStateFields: ["lastFetchedAt"]
57714
+ volatileStateFields: ["lastFetchedAt"],
57715
+ customize: {
57716
+ version: 1,
57717
+ advanced: "derive",
57718
+ targets: []
57719
+ }
55365
57720
  };
55366
57721
  /**
55367
57722
  * Per-class audio metrics aggregated over a sliding window.
@@ -55588,7 +57943,10 @@ var BatteryStatusSchema = object({
55588
57943
  * Consumers must SKIP a null rather than coerce it — `battery-band` already
55589
57944
  * declines to band a non-finite reading, which is the correct shape.
55590
57945
  */
55591
- percentage: number().min(0).max(100).nullable(),
57946
+ percentage: number().min(0).max(100).nullable().meta({
57947
+ unit: "%",
57948
+ label: "Charge"
57949
+ }),
55592
57950
  /**
55593
57951
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
55594
57952
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -55607,13 +57965,13 @@ var BatteryStatusSchema = object({
55607
57965
  "solar",
55608
57966
  "none",
55609
57967
  "unknown"
55610
- ]),
57968
+ ]).meta({ label: "Charging source" }),
55611
57969
  /**
55612
57970
  * True when the camera firmware has gone into low-power mode. Battery
55613
57971
  * providers MUST avoid polling during sleep — reading the battery
55614
57972
  * wakes the camera up and drains charge.
55615
57973
  */
55616
- sleeping: boolean(),
57974
+ sleeping: boolean().meta({ label: "Sleeping" }),
55617
57975
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
55618
57976
  lastUpdated: number(),
55619
57977
  /**
@@ -55653,22 +58011,71 @@ var BatteryStatusSchema = object({
55653
58011
  * sub-threshold = low). UI MUST render "Normal"/"Low" instead of a
55654
58012
  * misleading exact percentage. Absent/false → genuine 0–100 % reading.
55655
58013
  */
55656
- binary: boolean().optional()
58014
+ binary: boolean().optional().meta({ label: "Binary indicator" })
55657
58015
  });
58016
+ var BATTERY_DEVICE_TYPES = [
58017
+ DeviceType.Camera,
58018
+ DeviceType.Sensor,
58019
+ DeviceType.Button,
58020
+ DeviceType.Switch,
58021
+ DeviceType.PetFeeder,
58022
+ DeviceType.Container,
58023
+ DeviceType.Thermostat
58024
+ ];
58025
+ /** Generic Customize target for the percentage reading (D936). */
58026
+ var batteryCustomize = {
58027
+ version: 1,
58028
+ advanced: "derive",
58029
+ targets: [{
58030
+ id: "percentage",
58031
+ cardinality: "scalar",
58032
+ vocabulary: {
58033
+ cap: "battery",
58034
+ stateField: "percentage"
58035
+ },
58036
+ deviceTypes: BATTERY_DEVICE_TYPES,
58037
+ apply: "add-or-replace",
58038
+ path: "percentage",
58039
+ sources: [{
58040
+ kind: "field",
58041
+ valueKinds: ["number", "string"],
58042
+ transforms: [{ kind: "identity" }, {
58043
+ kind: "linear",
58044
+ defaultScale: 1,
58045
+ defaultOffset: 0,
58046
+ clampMin: 0,
58047
+ clampMax: 100
58048
+ }]
58049
+ }],
58050
+ companions: [
58051
+ {
58052
+ kind: "constant",
58053
+ path: "charging",
58054
+ value: "unknown",
58055
+ when: "add"
58056
+ },
58057
+ {
58058
+ kind: "constant",
58059
+ path: "sleeping",
58060
+ value: false,
58061
+ when: "add"
58062
+ },
58063
+ {
58064
+ kind: "clock",
58065
+ path: "lastUpdated",
58066
+ when: "add"
58067
+ }
58068
+ ],
58069
+ sourceReport: { status: "assignment-status" },
58070
+ advancedExpression: true
58071
+ }]
58072
+ };
55658
58073
  var batteryCapability = {
55659
58074
  name: "battery",
55660
58075
  scope: "device",
55661
58076
  deviceNative: true,
55662
58077
  mode: "singleton",
55663
- deviceTypes: [
55664
- DeviceType.Camera,
55665
- DeviceType.Sensor,
55666
- DeviceType.Button,
55667
- DeviceType.Switch,
55668
- DeviceType.PetFeeder,
55669
- DeviceType.Container,
55670
- DeviceType.Thermostat
55671
- ],
58078
+ deviceTypes: BATTERY_DEVICE_TYPES,
55672
58079
  methods: {
55673
58080
  /**
55674
58081
  * Explicitly wake the camera from low-power sleep ahead of a
@@ -55752,6 +58159,7 @@ onStatusChanged: { data: object({
55752
58159
  kind: "gauge",
55753
58160
  unit: "%"
55754
58161
  } } },
58162
+ customize: batteryCustomize,
55755
58163
  /** Clock fields: written, but excluded from the compare that decides
55756
58164
  * whether persisting is worth a SQLite commit. */
55757
58165
  volatileStateFields: ["lastUpdated"]
@@ -55768,7 +58176,7 @@ onStatusChanged: { data: object({
55768
58176
  * with the right HomeKit / Alexa display category.
55769
58177
  */
55770
58178
  var BinaryStatusSchema = object({
55771
- on: boolean(),
58179
+ on: boolean().meta({ label: "On" }),
55772
58180
  /** Ms epoch of the last transition. 0 if never observed. */
55773
58181
  lastChangedAt: number()
55774
58182
  });
@@ -55797,7 +58205,12 @@ var binaryCapability = {
55797
58205
  history: { fields: { on: { kind: "boolean" } } },
55798
58206
  /** Clock fields: written, but excluded from the compare that decides
55799
58207
  * whether persisting is worth a SQLite commit. */
55800
- volatileStateFields: ["lastChangedAt"]
58208
+ volatileStateFields: ["lastChangedAt"],
58209
+ customize: {
58210
+ version: 1,
58211
+ advanced: "derive",
58212
+ targets: []
58213
+ }
55801
58214
  };
55802
58215
  /**
55803
58216
  * Dimmable-light brightness control. Co-exists with `switch` on the
@@ -56103,7 +58516,7 @@ var GridLayoutCellSchema = object({
56103
58516
  *
56104
58517
  * A grid's `high` composes its sources' `high` and its `low` their `low`, so a
56105
58518
  * profile is on offer only when EVERY source can serve it. The refusal NAMES
56106
- * the sources, because "this grid has no low" is not a finding — "615 has no
58519
+ * the sources, because "this grid has no low" is not a finding — "101 has no
56107
58520
  * low" is, and it is the one an operator can act on.
56108
58521
  */
56109
58522
  var GridProfileOfferSchema = object({
@@ -56712,6 +59125,106 @@ var ConsumablesStatusSchema = object({
56712
59125
  items: array(ConsumableItemSchema),
56713
59126
  lastChangedAt: number()
56714
59127
  });
59128
+ /** Synthesize seed for a link-built status (no native provider).
59129
+ *
59130
+ * ⚠ NO LIVE CALLER since 2026-08-08 (device-links deleted; see
59131
+ * `CapabilityStatusSchema.empty`). The wiring guidance below was written for
59132
+ * exactly the case the operator is asking about again — a Dreame's HA
59133
+ * consumable-life sensors — so it is kept for that conversation, not because
59134
+ * anything reads it today. */
59135
+ var EMPTY_STATUS = {
59136
+ items: [],
59137
+ lastChangedAt: 0
59138
+ };
59139
+ /** Seed for a NEW link-built consumable item. `key`/`label` are overwritten
59140
+ * with the link's `itemKey` (see `status.itemArray`), so the placeholder
59141
+ * empty strings never survive into a validated item. Link-built items are
59142
+ * not resettable — there is no native provider to receive `reset()`.
59143
+ *
59144
+ * Wiring guidance (HA vacuum consumable-life sensors):
59145
+ * - a percent-remaining source (`numeric-sensor`, unit '%') → `level` via
59146
+ * `identity` (or `linear` scale 1 offset 0 clamp [0,100] to be safe);
59147
+ * - an hours-remaining source (e.g. Dreame 'Main Brush Time Left', unit 'h')
59148
+ * → `level` via `linear` with scale = 100 / max-hours for that item
59149
+ * (e.g. main brush 300 h → scale 0.3333) + clamp [0,100];
59150
+ * - a discrete source (`enum-sensor`, e.g. mop pad 'installed') → `status`
59151
+ * via `enum-map` (e.g. { installed: 'ok', missing: 'replace' }).
59152
+ * A numeric→'replace' THRESHOLD (level < 10 → 'replace') is NOT expressible
59153
+ * with the current transform kinds — leave `status` null (valid) until the
59154
+ * expression transform lands. */
59155
+ /** Generic Customize target for one consumable item (D936). Native rows stay read-only. */
59156
+ var consumablesCustomize = {
59157
+ version: 1,
59158
+ targets: [{
59159
+ id: "items",
59160
+ cardinality: "keyedArray",
59161
+ vocabulary: { cap: "consumables" },
59162
+ deviceTypes: Object.values(DeviceType),
59163
+ apply: "add",
59164
+ path: "items",
59165
+ keyField: "key",
59166
+ labelField: "label",
59167
+ itemSchema: ConsumableItemSchema,
59168
+ nativeItems: "read-only",
59169
+ sourceReport: { status: "assignment-status" },
59170
+ fields: [
59171
+ {
59172
+ path: "level",
59173
+ sources: [{
59174
+ kind: "numeric",
59175
+ transforms: [{ kind: "identity" }, {
59176
+ kind: "linear",
59177
+ defaultScale: 1,
59178
+ defaultOffset: 0,
59179
+ clampMin: 0,
59180
+ clampMax: 100
59181
+ }]
59182
+ }]
59183
+ },
59184
+ {
59185
+ path: "remaining.value",
59186
+ sources: [{
59187
+ kind: "numeric",
59188
+ transforms: [{ kind: "identity" }]
59189
+ }],
59190
+ literals: [{
59191
+ path: "remaining.unit",
59192
+ values: [...ConsumableRemainingUnitSchema.options]
59193
+ }]
59194
+ },
59195
+ {
59196
+ path: "status",
59197
+ sources: [{
59198
+ kind: "enum",
59199
+ transforms: [{
59200
+ kind: "enum-map",
59201
+ outputValues: [...ConsumableStatusSchema.options],
59202
+ unmapped: null
59203
+ }]
59204
+ }]
59205
+ }
59206
+ ],
59207
+ traits: [{
59208
+ path: "kind",
59209
+ values: [...ConsumableKindSchema.options],
59210
+ defaultValue: "wear"
59211
+ }, {
59212
+ path: "form",
59213
+ values: [...ConsumableFormSchema.options],
59214
+ defaultValue: "part"
59215
+ }],
59216
+ companions: [{
59217
+ kind: "clock",
59218
+ path: "lastChangedAt",
59219
+ when: "add"
59220
+ }, {
59221
+ kind: "clock",
59222
+ path: "lastFetchedAt",
59223
+ when: "add"
59224
+ }],
59225
+ advancedExpression: true
59226
+ }]
59227
+ };
56715
59228
  var consumablesCapability = {
56716
59229
  name: "consumables",
56717
59230
  scope: "device",
@@ -56749,10 +59262,7 @@ reset: method(object({
56749
59262
  status: {
56750
59263
  schema: ConsumablesStatusSchema,
56751
59264
  kind: "push",
56752
- empty: {
56753
- items: [],
56754
- lastChangedAt: 0
56755
- },
59265
+ empty: EMPTY_STATUS,
56756
59266
  itemArray: {
56757
59267
  path: "items",
56758
59268
  keyField: "key",
@@ -56788,6 +59298,7 @@ reset: method(object({
56788
59298
  * brush's remaining life and a dishwasher's salt are each recorded the moment
56789
59299
  * their provider reports them; an item that appears later gets its series.
56790
59300
  */
59301
+ customize: consumablesCustomize,
56791
59302
  history: {
56792
59303
  fields: {},
56793
59304
  items: {
@@ -57167,6 +59678,30 @@ var dayNightCapability = {
57167
59678
  volatileStateFields: ["lastFetchedAt"]
57168
59679
  };
57169
59680
  /**
59681
+ * display-palette — the cluster's one colour table (D939).
59682
+ *
59683
+ * Hub singleton. `getPalette` reports `unknown` when the settings store
59684
+ * cannot be read; it does not pretend the bundled preset was stored.
59685
+ * `setPalette` refuses a palette that fails the ΔE / contrast rule and names
59686
+ * the pairs.
59687
+ */
59688
+ var presetSummarySchema = object({
59689
+ id: string(),
59690
+ name: string(),
59691
+ swatches: record(string(), paletteSwatchSchema),
59692
+ fallbacks: array(string())
59693
+ });
59694
+ method(_void(), paletteResultSchema, {
59695
+ auth: "protected",
59696
+ role: "viewer"
59697
+ }), method(_void(), array(presetSummarySchema).readonly(), {
59698
+ auth: "protected",
59699
+ role: "viewer"
59700
+ }), method(setPaletteInputSchema, paletteReadySchema, {
59701
+ kind: "mutation",
59702
+ auth: "admin"
59703
+ });
59704
+ /**
57170
59705
  * Generic device-level status snapshot. Auto-registered by `BaseDevice`
57171
59706
  * for every device, regardless of provider — the kernel needs a uniform
57172
59707
  * cap-keyed slice for the basic device flags every consumer expects to
@@ -57530,6 +60065,36 @@ var dishwasherCapability = {
57530
60065
  powerOn: { kind: "boolean" }
57531
60066
  } }
57532
60067
  };
60068
+ /** Pulse override: a rising edge advances `lastPressedAt` and the press count. */
60069
+ var doorbellCustomize = {
60070
+ version: 1,
60071
+ targets: [{
60072
+ id: "pressed",
60073
+ cardinality: "event",
60074
+ shape: "pulse",
60075
+ vocabulary: {
60076
+ cap: "doorbell",
60077
+ eventName: "onPressed"
60078
+ },
60079
+ deviceTypes: [DeviceType.Camera],
60080
+ apply: "add",
60081
+ applyAuthority: { kind: "composition-claim" },
60082
+ eventName: "onPressed",
60083
+ edges: ["rising"],
60084
+ timestampPath: "lastPressedAt",
60085
+ counterPath: "pressCountSinceStart",
60086
+ highWater: "composer-advance",
60087
+ combine: "any",
60088
+ debounce: {
60089
+ kind: "rising-edge",
60090
+ defaultDebounceMs: 2e3,
60091
+ changedAtRequired: true
60092
+ },
60093
+ sources: [{ kind: "binary" }, { kind: "switch" }],
60094
+ sourceReport: { status: "assignment-status" },
60095
+ advancedExpression: true
60096
+ }]
60097
+ };
57533
60098
  var DoorbellStatusSchema = object({
57534
60099
  /** Ms epoch of the last press. null = never observed since this provider started. */
57535
60100
  lastPressedAt: number().nullable(),
@@ -57596,7 +60161,8 @@ onPressed: {
57596
60161
  /**
57597
60162
  * History (D850): none — `pressCountSinceStart` resets with the addon, so it is not a monotonic meter; presses live in the events ledger.
57598
60163
  */
57599
- history: "none"
60164
+ history: "none",
60165
+ customize: doorbellCustomize
57600
60166
  };
57601
60167
  /**
57602
60168
  * Enum-state sensor — a string value picked from a finite option set.
@@ -58468,7 +61034,10 @@ var humidifierCapability = {
58468
61034
  */
58469
61035
  var HumiditySensorStatusSchema = object({
58470
61036
  /** Current relative humidity, 0..100. */
58471
- percent: number().min(0).max(100),
61037
+ percent: number().min(0).max(100).meta({
61038
+ unit: "%",
61039
+ label: "Humidity"
61040
+ }),
58472
61041
  /** Ms epoch when the slice was last updated. */
58473
61042
  lastFetchedAt: number(),
58474
61043
  /** Live display unit from the upstream source (e.g. HA
@@ -58510,7 +61079,12 @@ var humiditySensorCapability = {
58510
61079
  } } },
58511
61080
  /** Clock fields: written, but excluded from the compare that decides
58512
61081
  * whether persisting is worth a SQLite commit. */
58513
- volatileStateFields: ["lastFetchedAt"]
61082
+ volatileStateFields: ["lastFetchedAt"],
61083
+ customize: {
61084
+ version: 1,
61085
+ advanced: "derive",
61086
+ targets: []
61087
+ }
58514
61088
  };
58515
61089
  /**
58516
61090
  * Image display cap. Models a single still image exposed by an integration —
@@ -59992,6 +62566,38 @@ authKey: string().optional() }), object({
59992
62566
  /** Human-readable error when `ok: false`. */
59993
62567
  error: string().optional()
59994
62568
  }), { kind: "mutation" });
62569
+ /** Span override: start on a rising edge, end on a fall or this timeout. */
62570
+ var motionCustomize = {
62571
+ version: 1,
62572
+ targets: [{
62573
+ id: "detected",
62574
+ cardinality: "event",
62575
+ shape: "span",
62576
+ vocabulary: {
62577
+ cap: "motion",
62578
+ eventName: "onMotionChanged"
62579
+ },
62580
+ deviceTypes: [DeviceType.Camera],
62581
+ apply: "replace",
62582
+ applyAuthority: {
62583
+ kind: "camera-sensors",
62584
+ timeoutField: "motionCooldownMs"
62585
+ },
62586
+ eventName: "onMotionChanged",
62587
+ start: "rising-edge",
62588
+ end: "falling-edge-or-timeout",
62589
+ timeoutMs: 3e4,
62590
+ combine: "any",
62591
+ sourceModes: [
62592
+ "in-addition",
62593
+ "confirm",
62594
+ "replace"
62595
+ ],
62596
+ sources: [{ kind: "binary" }, { kind: "switch" }],
62597
+ sourceReport: { status: "assignment-status" },
62598
+ advancedExpression: false
62599
+ }]
62600
+ };
59995
62601
  var MotionStatusSchema = object({
59996
62602
  detected: boolean(),
59997
62603
  /** Ms epoch of the last detected-true observation. Null if never detected. */
@@ -60131,7 +62737,8 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
60131
62737
  history: { fields: { detected: {
60132
62738
  kind: "boolean",
60133
62739
  excludeDeviceTypes: [DeviceType.Camera]
60134
- } } }
62740
+ } } },
62741
+ customize: motionCustomize
60135
62742
  };
60136
62743
  /**
60137
62744
  * Motion-trigger toggle for accessory devices.
@@ -61950,6 +64557,30 @@ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly(
61950
64557
  kind: "mutation",
61951
64558
  auth: "admin"
61952
64559
  });
64560
+ var CORE_ULTRA_265K_IGPU_CLOCK_MHZ = 2e3;
64561
+ var positiveOrNull = number().nullable().transform((value) => value !== null && Number.isFinite(value) && value > 0 ? value : null);
64562
+ var textOrNull = string().nullable().transform((value) => value !== null && value.trim() !== "" ? value : null);
64563
+ var PrecisionGopsSchema = object({
64564
+ int8: positiveOrNull,
64565
+ fp16: positiveOrNull
64566
+ });
64567
+ /** What one accelerator device reported. Every failed query is null. */
64568
+ var AcceleratorComputeSchema = object({
64569
+ deviceKey: string(),
64570
+ fullDeviceName: textOrNull,
64571
+ executionUnits: positiveOrNull,
64572
+ clockMHz: positiveOrNull,
64573
+ gops: PrecisionGopsSchema.nullable(),
64574
+ architecture: textOrNull,
64575
+ npuName: textOrNull,
64576
+ tops: positiveOrNull,
64577
+ vendor: textOrNull,
64578
+ webgpuArchitecture: textOrNull,
64579
+ webgpuDevice: textOrNull,
64580
+ computeUnits: positiveOrNull
64581
+ });
64582
+ object({ accelerators: array(AcceleratorComputeSchema).nullable() });
64583
+ 64 * CORE_ULTRA_265K_IGPU_CLOCK_MHZ;
61953
64584
  var ModelFormatSchema = _enum(MODEL_FORMATS);
61954
64585
  var HwAccelBackendInputSchema = _enum([
61955
64586
  "videotoolbox",
@@ -62063,7 +64694,12 @@ var HardwareInfoSchema = object({
62063
64694
  availableRAM_MB: number(),
62064
64695
  gpu: GpuInfoSchema.nullable(),
62065
64696
  npu: NpuInfoSchema.nullable(),
62066
- coral: CoralInfoSchema.nullable().optional()
64697
+ coral: CoralInfoSchema.nullable().optional(),
64698
+ /**
64699
+ * Per-accelerator compute (D930). Omitted by a node that has not probed it.
64700
+ * `null` fields inside an entry are a failed query, never a zero.
64701
+ */
64702
+ accelerators: array(AcceleratorComputeSchema).readonly().optional()
62067
64703
  });
62068
64704
  var PlatformScoreSchema = object({
62069
64705
  runtime: literal("python"),
@@ -62147,9 +64783,15 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
62147
64783
  */
62148
64784
  var PowerMeterStatusSchema = object({
62149
64785
  /** Instantaneous power draw in watts. */
62150
- watts: number().optional(),
64786
+ watts: number().optional().meta({
64787
+ unit: "W",
64788
+ label: "Power"
64789
+ }),
62151
64790
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
62152
- kwhTotal: number().optional(),
64791
+ kwhTotal: number().optional().meta({
64792
+ unit: "kWh",
64793
+ label: "Energy"
64794
+ }),
62153
64795
  /** Voltage in volts. */
62154
64796
  volts: number().optional(),
62155
64797
  /** Current in amperes. */
@@ -62234,7 +64876,12 @@ var powerMeterCapability = {
62234
64876
  } },
62235
64877
  /** Clock fields: written, but excluded from the compare that decides
62236
64878
  * whether persisting is worth a SQLite commit. */
62237
- volatileStateFields: ["lastFetchedAt"]
64879
+ volatileStateFields: ["lastFetchedAt"],
64880
+ customize: {
64881
+ version: 1,
64882
+ advanced: "derive",
64883
+ targets: []
64884
+ }
62238
64885
  };
62239
64886
  /**
62240
64887
  * Presence cap. Models HA `person.*` and `device_tracker.*` entities
@@ -62679,9 +65326,9 @@ var PtzOptionsSchema = object({
62679
65326
  * Reolink preset 0, Hikvision preset '1', Dahua preset 1 -- and on this fleet
62680
65327
  * not one of the three cameras honours its own:
62681
65328
  *
62682
- * 592 Videocamera camera Daniel (reolink) preset 0 holds "stanza"
62683
- * 1438 Videocamera dispensa (hikvision) preset 1 holds "Credenza"
62684
- * 3836 Videocamera studio (amcrest) preset 1 holds "Preset1"
65329
+ * 107 Camera camera Carol (reolink) preset 0 holds "stanza"
65330
+ * 1438 Camera dispensa (hikvision) preset 1 holds "Credenza"
65331
+ * 3836 Camera studio (amcrest) preset 1 holds "Preset1"
62685
65332
  *
62686
65333
  * So `goHome` meant "go wherever the operator happened to save in slot 0 or 1",
62687
65334
  * and two of the three swallowed the failure in a bare `catch`. For autotrack
@@ -63006,6 +65653,126 @@ var ptzAutotrackCapability = {
63006
65653
  */
63007
65654
  history: "none"
63008
65655
  };
65656
+ var RUNNING_POWER_START_DELAY_MS = 3e4;
65657
+ var RUNNING_POWER_STOP_DELAY_MS = 18e4;
65658
+ var RunningStateSourceSchema = _enum(["native", "assigned"]);
65659
+ var RunningStateStatusSchema = object({
65660
+ /** null = unknown — never coerced to false (D393). */
65661
+ running: boolean().nullable(),
65662
+ /** Epoch ms the current boolean began; null while `running` is null. */
65663
+ since: number().nullable(),
65664
+ source: RunningStateSourceSchema.meta({ label: "Source" }),
65665
+ phase: string().nullable(),
65666
+ /** null until a reading has been published (D393). */
65667
+ lastFetchedAt: number().nullable()
65668
+ });
65669
+ var RunningFlipEventDataSchema = object({
65670
+ deviceId: number(),
65671
+ since: number().nullable(),
65672
+ phase: string().nullable()
65673
+ });
65674
+ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
65675
+ /** Generic Customize target for the running boolean (D936). */
65676
+ var runningCustomize = {
65677
+ version: 1,
65678
+ advanced: "derive",
65679
+ targets: [{
65680
+ id: "running",
65681
+ cardinality: "scalar",
65682
+ vocabulary: {
65683
+ cap: "running-state",
65684
+ stateField: "running"
65685
+ },
65686
+ deviceTypes: [
65687
+ DeviceType.Dishwasher,
65688
+ DeviceType.Vacuum,
65689
+ DeviceType.LawnMower,
65690
+ DeviceType.MediaPlayer,
65691
+ DeviceType.WaterHeater,
65692
+ DeviceType.Humidifier,
65693
+ DeviceType.Fan,
65694
+ DeviceType.Climate,
65695
+ DeviceType.Thermostat,
65696
+ DeviceType.PetFeeder
65697
+ ],
65698
+ apply: "add-or-replace",
65699
+ path: "running",
65700
+ sources: [
65701
+ {
65702
+ kind: "switch",
65703
+ transforms: [{ kind: "identity" }]
65704
+ },
65705
+ {
65706
+ kind: "binary",
65707
+ transforms: [{ kind: "identity" }, { kind: "invert" }]
65708
+ },
65709
+ {
65710
+ kind: "numeric",
65711
+ requiredUnit: "W",
65712
+ transforms: [{
65713
+ kind: "threshold",
65714
+ comparison: "gte",
65715
+ defaultThreshold: 5,
65716
+ defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
65717
+ defaultStopDwellMs: RUNNING_POWER_STOP_DELAY_MS,
65718
+ thresholdUnit: "W"
65719
+ }]
65720
+ }
65721
+ ],
65722
+ companions: [
65723
+ {
65724
+ kind: "constant",
65725
+ path: "source",
65726
+ value: "assigned",
65727
+ when: "always"
65728
+ },
65729
+ {
65730
+ kind: "constant",
65731
+ path: "phase",
65732
+ value: null,
65733
+ when: "always"
65734
+ },
65735
+ {
65736
+ kind: "clock",
65737
+ path: "lastFetchedAt",
65738
+ when: "always"
65739
+ },
65740
+ {
65741
+ kind: "transition-time",
65742
+ path: "since",
65743
+ sourceChangedAt: "prefer"
65744
+ }
65745
+ ],
65746
+ sourceReport: {
65747
+ status: "assignment-status",
65748
+ runtimeField: "source",
65749
+ nativeValue: "native",
65750
+ assignedValue: "assigned"
65751
+ },
65752
+ advancedExpression: true
65753
+ }]
65754
+ };
65755
+ var runningStateCapability = {
65756
+ name: "running-state",
65757
+ scope: "device",
65758
+ deviceNative: true,
65759
+ mode: "singleton",
65760
+ deviceTypes: RUNNING_DEVICE_TYPES,
65761
+ methods: {},
65762
+ events: {
65763
+ onStarted: { data: RunningFlipEventDataSchema },
65764
+ onFinished: { data: RunningFlipEventDataSchema }
65765
+ },
65766
+ status: {
65767
+ schema: RunningStateStatusSchema,
65768
+ kind: "push"
65769
+ },
65770
+ runtimeState: RunningStateStatusSchema,
65771
+ durability: "restored",
65772
+ history: { fields: { running: { kind: "boolean" } } },
65773
+ volatileStateFields: ["lastFetchedAt"],
65774
+ customize: runningCustomize
65775
+ };
63009
65776
  /**
63010
65777
  * reboot — device-scoped capability for "soft" device reboots (firmware
63011
65778
  * reboot via vendor protocol; cameras, NVRs, doorbells). Surfaces a
@@ -63072,7 +65839,7 @@ var RecordingAvailabilitySchema = object({
63072
65839
  * would look identical. But the answer used to say nothing about that, so a
63073
65840
  * caller asking "what can I export?" read the single preferred profile as
63074
65841
  * the only one that exists — on this deployment every camera records `high`
63075
- * AND `low`, the low tree holding 14 GB for camera 615 alone, and the export
65842
+ * AND `low`, the low tree holding 14 GB for camera 101 alone, and the export
63076
65843
  * UI could not see it.
63077
65844
  *
63078
65845
  * Cheap: it is the same shallow directory read the profile CHOICE already
@@ -63171,7 +65938,7 @@ var RecordingSourceOptionsSchema = object({
63171
65938
  * `sparse` = gaps are the absence of one, and must be drawn as such.
63172
65939
  *
63173
65940
  * Not an onboard-only concession: measured 2026-09-24, OUR bar covers 98.8 %
63174
- * of 592's day and 1.2 % of 1436's. It is a fact about a (source, camera)
65941
+ * of 107's day and 1.2 % of 1436's. It is a fact about a (source, camera)
63175
65942
  * pair, and ours answers it per camera from `deriveRecordingMode`. */
63176
65943
  coverage: _enum(["continuous", "sparse"]),
63177
65944
  /** Where the playhead may be put.
@@ -63247,7 +66014,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(RecordingSourceS
63247
66014
  * merely discouraged (D554 amended).
63248
66015
  *
63249
66016
  * It was learned the expensive way on `videoclips.listClips`: measured
63250
- * on the live hub 2026-09-20, device 592 bound to `recorder` AND
66017
+ * on the live hub 2026-09-20, device 107 bound to `recorder` AND
63251
66018
  * `provider-reolink`, a bare call with `limit: 3` answered SIX rows,
63252
66019
  * three from each source, merged — `device-collection-dispatch.ts`
63253
66020
  * leaves an unpinned fan-out un-narrowed, so absence buys the union the
@@ -63848,7 +66615,7 @@ var ExportSpeedSchema = number().min(.25).max(32);
63848
66615
  * on a 10 h window holding 29,393 s of footage every range landed late by the
63849
66616
  * gap accumulated before it — up to 6,607 s, well past EOF. Nothing matched,
63850
66617
  * the video was a uniform timelapse, and the log line reported the five ranges
63851
- * that had been ASKED for (2026-08-13, export `57d14363`, camera 615).
66618
+ * that had been ASKED for (2026-08-13, export `57d14363`, camera 101).
63852
66619
  *
63853
66620
  * Relative and not absolute epoch, because an absolute epoch would make every
63854
66621
  * call site responsible for the same subtraction.
@@ -64728,7 +67495,7 @@ getStatus: method(object({ deviceId: number() }), RecordingSignalStatusSchema) }
64728
67495
  * which put a "Scenes" tab on one camera's detail page. That is the wrong shape
64729
67496
  * for the thing: a scene is a standing question about the property ("is the bin
64730
67497
  * still out"), and the operator's question is "which of my scenes have tripped",
64731
- * across every camera at once — not "what does camera 617 think". Buried one
67498
+ * across every camera at once — not "what does camera 102 think". Buried one
64732
67499
  * camera deep it also could not be found. The surface is now a top-level admin
64733
67500
  * page (`/scenes`, `pages/Scenes.tsx`) that lists every scene on every camera and
64734
67501
  * picks the camera inside the create flow, the same shape Events and Faces have.
@@ -65177,7 +67944,20 @@ var ZoneRuleSchema = object({
65177
67944
  * Defaults to `true` so operators creating a rule via the UI
65178
67945
  * see it active immediately.
65179
67946
  */
65180
- enabled: boolean().default(true)
67947
+ enabled: boolean().default(true),
67948
+ /**
67949
+ * Package stage only. When true, a package candidate may open from a
67950
+ * scene difference in this rule's zone after a person leaves. The
67951
+ * package model, when it boxes something overlapping, is extra evidence
67952
+ * and is not the gate. Absent or false keeps today's model path.
67953
+ */
67954
+ detectBySceneDifference: boolean().optional(),
67955
+ /**
67956
+ * Package stage only. When true, a promoted package is shown to the
67957
+ * `llm` cap before the delivery event is emitted. Absent or false emits
67958
+ * as today. Usable with or without `detectBySceneDifference`.
67959
+ */
67960
+ confirmWithLlm: boolean().optional()
65181
67961
  });
65182
67962
  array(ZoneRuleSchema).readonly();
65183
67963
  /**
@@ -65772,7 +68552,7 @@ function buildStreamParamsConfigSchema(options, status) {
65772
68552
  * `getSettingsUISchema()` surface.
65773
68553
  */
65774
68554
  var SwitchStatusSchema = object({
65775
- on: boolean(),
68555
+ on: boolean().meta({ label: "On" }),
65776
68556
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
65777
68557
  lastChangedAt: number()
65778
68558
  });
@@ -65831,7 +68611,12 @@ var switchCapability = {
65831
68611
  label: "On",
65832
68612
  kind: "boolean"
65833
68613
  }
65834
- }] }
68614
+ }] },
68615
+ customize: {
68616
+ version: 1,
68617
+ advanced: "derive",
68618
+ targets: []
68619
+ }
65835
68620
  };
65836
68621
  /** C0 controls, DEL and the C1 range: none of them belongs in a name. */
65837
68622
  function hasControlCharacter(value) {
@@ -66427,7 +69212,10 @@ var tamperCapability = {
66427
69212
  */
66428
69213
  var TemperatureSensorStatusSchema = object({
66429
69214
  /** Current temperature in Celsius. */
66430
- celsius: number(),
69215
+ celsius: number().meta({
69216
+ unit: "°C",
69217
+ label: "Temperature"
69218
+ }),
66431
69219
  /** Ms epoch when the slice was last updated (push or poll). */
66432
69220
  lastFetchedAt: number(),
66433
69221
  /** Live display unit from the upstream source (e.g. HA
@@ -66470,7 +69258,12 @@ var temperatureSensorCapability = {
66470
69258
  } } },
66471
69259
  /** Clock fields: written, but excluded from the compare that decides
66472
69260
  * whether persisting is worth a SQLite commit. */
66473
- volatileStateFields: ["lastFetchedAt"]
69261
+ volatileStateFields: ["lastFetchedAt"],
69262
+ customize: {
69263
+ version: 1,
69264
+ advanced: "derive",
69265
+ targets: []
69266
+ }
66474
69267
  };
66475
69268
  /**
66476
69269
  * toast — system-scoped singleton capability that streams toast
@@ -67733,7 +70526,7 @@ method(object({}), array(TrainingProviderDescriptorSchema).readonly(), { auth: "
67733
70526
  * - **Jobs.** A persisted state machine, a reconcile loop against the
67734
70527
  * provider, a cost guard, a daily orphan sweep and the retention rules.
67735
70528
  * - **The return flow.** Verified artefacts → Model Studio
67736
- * (`custom-model-registry.importModelBundle`) → canary on cameras →
70529
+ * (`custom-model-registry.importModelBundle`) → canary on accelerators →
67737
70530
  * rollback. Nothing is ever registered automatically.
67738
70531
  *
67739
70532
  * Plan/start takes a live {@link TrainingCorpusSelection} (collections +
@@ -67870,20 +70663,24 @@ var TrainingProgressPointSchema = object({
67870
70663
  map50: number().nullable(),
67871
70664
  map50_95: number().nullable()
67872
70665
  });
70666
+ /** One accelerator: a `(node, inference device)` that runs the root detector. */
70667
+ var TrainingAcceleratorRefSchema = object({
70668
+ nodeId: string(),
70669
+ deviceKey: string()
70670
+ });
70671
+ /**
70672
+ * A canary pins the registered model on chosen ACCELERATORS — a model is
70673
+ * chosen by the accelerator that runs it (D927); every camera balanced onto
70674
+ * one runs it. `previous` is the root-detector pin each one had (`null` = it
70675
+ * ran its default), exactly, so rollback restores it.
70676
+ */
67873
70677
  var TrainingCanarySchema = object({
67874
- deviceIds: array(number().int()).readonly(),
70678
+ accelerators: array(TrainingAcceleratorRefSchema).readonly(),
67875
70679
  since: number(),
67876
- /** Every override the canary replaced, exactly, so rollback restores it. */
67877
- previous: array(object({
67878
- deviceId: number().int(),
67879
- nodeId: string(),
67880
- deviceKey: string(),
67881
- patch: object({
67882
- modelId: string().optional(),
67883
- settings: record(string(), unknown()).readonly().optional()
67884
- }).nullable()
67885
- })).readonly()
70680
+ previous: array(TrainingAcceleratorRefSchema.extend({ modelId: string().nullable() })).readonly()
67886
70681
  });
70682
+ /** An accelerator a canary may pin: it runs the root detector, on this model now. */
70683
+ var TrainingCanaryTargetSchema = TrainingAcceleratorRefSchema.extend({ pinnedModelId: string().nullable() });
67887
70684
  var TrainingJobSchema = object({
67888
70685
  id: string(),
67889
70686
  idempotencyKey: string(),
@@ -67995,11 +70792,11 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
67995
70792
  kind: "mutation",
67996
70793
  auth: "admin",
67997
70794
  timeoutMs: 12e4
67998
- }), method(IdInput, TrainingResultSchema.nullable(), { auth: "admin" }), method(IdInput.extend({ canaryDeviceIds: array(number().int()).readonly() }), TrainingJobSchema, {
70795
+ }), method(IdInput, TrainingResultSchema.nullable(), { auth: "admin" }), method(_void(), array(TrainingCanaryTargetSchema).readonly(), { auth: "admin" }), method(IdInput.extend({ canaryAccelerators: array(TrainingAcceleratorRefSchema).readonly() }), TrainingJobSchema, {
67999
70796
  kind: "mutation",
68000
70797
  auth: "admin",
68001
70798
  timeoutMs: 30 * 6e4
68002
- }), method(IdInput.extend({ deviceIds: array(number().int()).min(1).readonly() }), TrainingJobSchema, {
70799
+ }), method(IdInput.extend({ accelerators: array(TrainingAcceleratorRefSchema).min(1).readonly() }), TrainingJobSchema, {
68003
70800
  kind: "mutation",
68004
70801
  auth: "admin",
68005
70802
  timeoutMs: 12e4
@@ -68145,6 +70942,10 @@ function withClipEventLabels(provider, deps) {
68145
70942
  };
68146
70943
  }
68147
70944
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
70945
+ 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;
70946
+ String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
70947
+ DeviceRole.BinarySensor, DeviceRole.MotionSensor;
70948
+ new Set(CAP_NAMES);
68148
70949
  Object.freeze({
68149
70950
  person: .5,
68150
70951
  vehicle: .5,
@@ -68510,6 +71311,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
68510
71311
  ptzAutotrack: ptzAutotrackCapability,
68511
71312
  recordingOnboard: recordingOnboardCapability,
68512
71313
  recordingSignal: recordingSignalCapability,
71314
+ runningState: runningStateCapability,
68513
71315
  sceneMonitor: sceneMonitorCapability,
68514
71316
  scriptRunner: scriptRunnerCapability,
68515
71317
  smoke: smokeCapability,
@@ -69392,7 +72194,7 @@ var BaseDeviceProvider = class extends BaseAddon {
69392
72194
  * A top-level persisted row with NO configuration is a leftover, not a
69393
72195
  * device — quarantine it instead of dialling it.
69394
72196
  *
69395
- * Device 614 was deleted, resurrected as a config-less shell by a write
72197
+ * Device 105 was deleted, resurrected as a config-less shell by a write
69396
72198
  * already in flight (D376), and then dialled at every single boot: eight
69397
72199
  * `Failed to restore device — bounded retry scheduled` lines in one day,
69398
72200
  * each one the same Zod refusal on `host` and `password`. The bound was
@@ -72702,6 +75504,27 @@ Object.freeze({
72702
75504
  access: "create",
72703
75505
  role: "viewer"
72704
75506
  },
75507
+ "displayPalette.getPalette": {
75508
+ capName: "display-palette",
75509
+ capScope: "system",
75510
+ addonId: null,
75511
+ access: "view",
75512
+ role: "viewer"
75513
+ },
75514
+ "displayPalette.listPresets": {
75515
+ capName: "display-palette",
75516
+ capScope: "system",
75517
+ addonId: null,
75518
+ access: "view",
75519
+ role: "viewer"
75520
+ },
75521
+ "displayPalette.setPalette": {
75522
+ capName: "display-palette",
75523
+ capScope: "system",
75524
+ addonId: null,
75525
+ access: "create",
75526
+ role: "admin"
75527
+ },
72705
75528
  "doorbell.getStatus": {
72706
75529
  capName: "doorbell",
72707
75530
  capScope: "device",
@@ -75621,20 +78444,6 @@ Object.freeze({
75621
78444
  access: "create",
75622
78445
  role: "admin"
75623
78446
  },
75624
- "pipelineExecutor.clearDeviceOverrides": {
75625
- capName: "pipeline-executor",
75626
- capScope: "system",
75627
- addonId: null,
75628
- access: "delete",
75629
- role: "admin"
75630
- },
75631
- "pipelineExecutor.clearModelBoundDeviceOverrides": {
75632
- capName: "pipeline-executor",
75633
- capScope: "system",
75634
- addonId: null,
75635
- access: "delete",
75636
- role: "admin"
75637
- },
75638
78447
  "pipelineExecutor.deleteModel": {
75639
78448
  capName: "pipeline-executor",
75640
78449
  capScope: "system",
@@ -75677,13 +78486,6 @@ Object.freeze({
75677
78486
  access: "view",
75678
78487
  role: "admin"
75679
78488
  },
75680
- "pipelineExecutor.getDefaultSteps": {
75681
- capName: "pipeline-executor",
75682
- capScope: "system",
75683
- addonId: null,
75684
- access: "view",
75685
- role: "admin"
75686
- },
75687
78489
  "pipelineExecutor.getDetectionConfigSchema": {
75688
78490
  capName: "pipeline-executor",
75689
78491
  capScope: "system",
@@ -75705,20 +78507,6 @@ Object.freeze({
75705
78507
  access: "view",
75706
78508
  role: "admin"
75707
78509
  },
75708
- "pipelineExecutor.getGlobalPipelineConfig": {
75709
- capName: "pipeline-executor",
75710
- capScope: "system",
75711
- addonId: null,
75712
- access: "view",
75713
- role: "admin"
75714
- },
75715
- "pipelineExecutor.getGlobalSteps": {
75716
- capName: "pipeline-executor",
75717
- capScope: "system",
75718
- addonId: null,
75719
- access: "view",
75720
- role: "admin"
75721
- },
75722
78510
  "pipelineExecutor.getInferenceDeviceHealth": {
75723
78511
  capName: "pipeline-executor",
75724
78512
  capScope: "system",
@@ -75978,13 +78766,6 @@ Object.freeze({
75978
78766
  access: "view",
75979
78767
  role: "admin"
75980
78768
  },
75981
- "pipelineOrchestrator.getCameraStepOverrides": {
75982
- capName: "pipeline-orchestrator",
75983
- capScope: "system",
75984
- addonId: null,
75985
- access: "view",
75986
- role: "admin"
75987
- },
75988
78769
  "pipelineOrchestrator.getCameraSwitches": {
75989
78770
  capName: "pipeline-orchestrator",
75990
78771
  capScope: "system",
@@ -76223,13 +79004,6 @@ Object.freeze({
76223
79004
  access: "create",
76224
79005
  role: "admin"
76225
79006
  },
76226
- "pipelineOrchestrator.setCameraPipelineForAgent": {
76227
- capName: "pipeline-orchestrator",
76228
- capScope: "system",
76229
- addonId: null,
76230
- access: "create",
76231
- role: "admin"
76232
- },
76233
79007
  "pipelineOrchestrator.setCameraSensors": {
76234
79008
  capName: "pipeline-orchestrator",
76235
79009
  capScope: "system",
@@ -76237,42 +79011,42 @@ Object.freeze({
76237
79011
  access: "create",
76238
79012
  role: "admin"
76239
79013
  },
76240
- "pipelineOrchestrator.setCameraStepOverride": {
79014
+ "pipelineOrchestrator.setCameraStepSettings": {
76241
79015
  capName: "pipeline-orchestrator",
76242
79016
  capScope: "system",
76243
79017
  addonId: null,
76244
79018
  access: "create",
76245
79019
  role: "admin"
76246
79020
  },
76247
- "pipelineOrchestrator.setCameraStepSettings": {
79021
+ "pipelineOrchestrator.setCameraStepToggle": {
76248
79022
  capName: "pipeline-orchestrator",
76249
79023
  capScope: "system",
76250
79024
  addonId: null,
76251
79025
  access: "create",
76252
79026
  role: "admin"
76253
79027
  },
76254
- "pipelineOrchestrator.setCameraStepToggle": {
79028
+ "pipelineOrchestrator.setCameraSwitch": {
76255
79029
  capName: "pipeline-orchestrator",
76256
79030
  capScope: "system",
76257
79031
  addonId: null,
76258
79032
  access: "create",
76259
79033
  role: "admin"
76260
79034
  },
76261
- "pipelineOrchestrator.setCameraSwitch": {
79035
+ "pipelineOrchestrator.setCapabilityBinding": {
76262
79036
  capName: "pipeline-orchestrator",
76263
79037
  capScope: "system",
76264
79038
  addonId: null,
76265
79039
  access: "create",
76266
79040
  role: "admin"
76267
79041
  },
76268
- "pipelineOrchestrator.setCapabilityBinding": {
79042
+ "pipelineOrchestrator.setLoadBalancingShares": {
76269
79043
  capName: "pipeline-orchestrator",
76270
79044
  capScope: "system",
76271
79045
  addonId: null,
76272
79046
  access: "create",
76273
79047
  role: "admin"
76274
79048
  },
76275
- "pipelineOrchestrator.setLoadBalancingShares": {
79049
+ "pipelineOrchestrator.setNodeStepSettings": {
76276
79050
  capName: "pipeline-orchestrator",
76277
79051
  capScope: "system",
76278
79052
  addonId: null,
@@ -77301,6 +80075,13 @@ Object.freeze({
77301
80075
  access: "create",
77302
80076
  role: "admin"
77303
80077
  },
80078
+ "runningState.getStatus": {
80079
+ capName: "running-state",
80080
+ capScope: "device",
80081
+ addonId: null,
80082
+ access: "view",
80083
+ role: "viewer"
80084
+ },
77304
80085
  "sceneMonitor.captureReference": {
77305
80086
  capName: "scene-monitor",
77306
80087
  capScope: "device",
@@ -78631,6 +81412,13 @@ Object.freeze({
78631
81412
  access: "view",
78632
81413
  role: "admin"
78633
81414
  },
81415
+ "training.listCanaryTargets": {
81416
+ capName: "training",
81417
+ capScope: "system",
81418
+ addonId: null,
81419
+ access: "view",
81420
+ role: "admin"
81421
+ },
78634
81422
  "training.listJobs": {
78635
81423
  capName: "training",
78636
81424
  capScope: "system",
@@ -82008,6 +84796,32 @@ var APPLIANCE_CAP_VOCABULARY = {
82008
84796
  }],
82009
84797
  events: { onSent: { notOperatorFacing: "a delivery receipt of a send this system made — not a fact about the world" } }
82010
84798
  },
84799
+ "running-state": {
84800
+ scope: "device",
84801
+ noun: t("Running", "In funzione"),
84802
+ state: [{
84803
+ kind: "boolean",
84804
+ field: "running",
84805
+ label: t("Running", "In funzione"),
84806
+ whenTrue: t("When {device} starts", "Quando {device} inizia"),
84807
+ whenFalse: t("When {device} finishes", "Quando {device} finisce"),
84808
+ icon: "play"
84809
+ }],
84810
+ events: {
84811
+ onStarted: {
84812
+ category: EventCategory.RunningStarted,
84813
+ label: t("Started running", "Ha iniziato a funzionare"),
84814
+ phrase: t("When {device} starts running", "Quando {device} inizia a funzionare"),
84815
+ icon: "play"
84816
+ },
84817
+ onFinished: {
84818
+ category: EventCategory.RunningFinished,
84819
+ label: t("Finished", "Ha finito"),
84820
+ phrase: t("When {device} finishes", "Quando {device} finisce"),
84821
+ icon: "square"
84822
+ }
84823
+ }
84824
+ },
82011
84825
  update: {
82012
84826
  scope: "device",
82013
84827
  noun: t("Firmware update", "Aggiornamento firmware"),
@@ -82628,7 +85442,7 @@ var SENSOR_CAP_VOCABULARY = {
82628
85442
  state: [{
82629
85443
  kind: "boolean",
82630
85444
  field: "on",
82631
- label: t("Active", "Attivo"),
85445
+ label: t("On", "Acceso"),
82632
85446
  whenTrue: t("When {device} turns active", "Quando {device} si attiva"),
82633
85447
  whenFalse: t("When {device} turns inactive", "Quando {device} si disattiva"),
82634
85448
  icon: "toggle-right"
@@ -83167,6 +85981,7 @@ var SYSTEM_CAP_VOCABULARY = {
83167
85981
  "device-provider": system(INTERNAL),
83168
85982
  "device-removal-hook": system(INTERNAL),
83169
85983
  "device-state": system("the runtime-state mirror every trigger already reads through"),
85984
+ "display-palette": system("the cluster display palette — one colour table for every client, not a device action"),
83170
85985
  "embedding-encoder": system(ML),
83171
85986
  "face-gallery": system("the face gallery — curated on its own page"),
83172
85987
  "failure-contribution": system(INTERNAL),
@@ -85169,11 +87984,6 @@ Object.freeze({
85169
87984
  form: "single",
85170
87985
  optional: false
85171
87986
  }],
85172
- "pipelineExecutor.clearModelBoundDeviceOverrides": [{
85173
- name: "deviceIds",
85174
- form: "array",
85175
- optional: true
85176
- }],
85177
87987
  "pipelineExecutor.runPipeline": [{
85178
87988
  name: "deviceId",
85179
87989
  form: "single",
@@ -85229,11 +88039,6 @@ Object.freeze({
85229
88039
  form: "array",
85230
88040
  optional: true
85231
88041
  }],
85232
- "pipelineOrchestrator.getCameraStepOverrides": [{
85233
- name: "deviceId",
85234
- form: "single",
85235
- optional: false
85236
- }],
85237
88042
  "pipelineOrchestrator.getCameraSwitches": [{
85238
88043
  name: "deviceId",
85239
88044
  form: "single",
@@ -85274,21 +88079,11 @@ Object.freeze({
85274
88079
  form: "single",
85275
88080
  optional: false
85276
88081
  }],
85277
- "pipelineOrchestrator.setCameraPipelineForAgent": [{
85278
- name: "deviceId",
85279
- form: "single",
85280
- optional: false
85281
- }],
85282
88082
  "pipelineOrchestrator.setCameraSensors": [{
85283
88083
  name: "deviceId",
85284
88084
  form: "single",
85285
88085
  optional: false
85286
88086
  }],
85287
- "pipelineOrchestrator.setCameraStepOverride": [{
85288
- name: "deviceId",
85289
- form: "single",
85290
- optional: false
85291
- }],
85292
88087
  "pipelineOrchestrator.setCameraStepSettings": [{
85293
88088
  name: "deviceId",
85294
88089
  form: "single",
@@ -85720,6 +88515,11 @@ Object.freeze({
85720
88515
  form: "single",
85721
88516
  optional: true
85722
88517
  }],
88518
+ "runningState.getStatus": [{
88519
+ name: "deviceId",
88520
+ form: "single",
88521
+ optional: false
88522
+ }],
85723
88523
  "sceneMonitor.captureReference": [{
85724
88524
  name: "deviceId",
85725
88525
  form: "single",
@@ -85966,11 +88766,6 @@ Object.freeze({
85966
88766
  form: "single",
85967
88767
  optional: false
85968
88768
  }],
85969
- "training.canaryResult": [{
85970
- name: "deviceIds",
85971
- form: "array",
85972
- optional: false
85973
- }],
85974
88769
  "update.getStatus": [{
85975
88770
  name: "deviceId",
85976
88771
  form: "single",
@@ -86223,6 +89018,94 @@ Object.freeze({
86223
89018
  "smtp-provider": "email"
86224
89019
  });
86225
89020
  DeviceType.Camera;
89021
+ /**
89022
+ * A saved Customize assignment (D936). The schema is the type: callers use
89023
+ * `z.infer`, they do not restate the shape.
89024
+ */
89025
+ var OverrideSourceSchema = object({
89026
+ addonId: string().min(1),
89027
+ stableId: string().min(1),
89028
+ cap: string().min(1),
89029
+ fieldPath: string().min(1)
89030
+ });
89031
+ var CustomizeTransformDraftSchema = discriminatedUnion("kind", [
89032
+ object({ kind: literal("identity") }),
89033
+ object({ kind: literal("invert") }),
89034
+ object({
89035
+ kind: literal("threshold"),
89036
+ comparison: _enum(["gte", "lte"]),
89037
+ threshold: number(),
89038
+ startDwellMs: number().nonnegative(),
89039
+ stopDwellMs: number().nonnegative()
89040
+ }),
89041
+ object({
89042
+ kind: literal("linear"),
89043
+ scale: number(),
89044
+ offset: number(),
89045
+ clampMin: number().optional(),
89046
+ clampMax: number().optional()
89047
+ }),
89048
+ object({
89049
+ kind: literal("enum-map"),
89050
+ mapping: record(string(), string().nullable())
89051
+ }),
89052
+ object({ kind: literal("number") })
89053
+ ]);
89054
+ var ScalarOverrideDraftSchema = object({
89055
+ kind: literal("scalar"),
89056
+ cap: string().min(1),
89057
+ targetId: string().min(1),
89058
+ source: OverrideSourceSchema,
89059
+ transform: CustomizeTransformDraftSchema
89060
+ });
89061
+ var KeyedArrayOverrideDraftSchema = object({
89062
+ kind: literal("keyedArray"),
89063
+ cap: string().min(1),
89064
+ targetId: string().min(1),
89065
+ key: string().min(1),
89066
+ label: string().min(1),
89067
+ fieldPath: string().min(1),
89068
+ source: OverrideSourceSchema,
89069
+ transform: CustomizeTransformDraftSchema
89070
+ });
89071
+ var PulseOverrideDraftSchema = object({
89072
+ kind: literal("pulse"),
89073
+ cap: string().min(1),
89074
+ targetId: string().min(1),
89075
+ enabled: boolean(),
89076
+ debounceMs: number().nonnegative(),
89077
+ sources: array(OverrideSourceSchema).min(1)
89078
+ });
89079
+ var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: _enum([
89080
+ "in-addition",
89081
+ "confirm",
89082
+ "replace"
89083
+ ]).optional() });
89084
+ discriminatedUnion("kind", [
89085
+ ScalarOverrideDraftSchema,
89086
+ KeyedArrayOverrideDraftSchema,
89087
+ PulseOverrideDraftSchema,
89088
+ object({
89089
+ kind: literal("span"),
89090
+ cap: string().min(1),
89091
+ targetId: string().min(1),
89092
+ timeoutMs: number().nonnegative(),
89093
+ cooldownMs: number().nonnegative().optional(),
89094
+ sources: array(SpanSourceDraftSchema)
89095
+ })
89096
+ ]);
89097
+ object({
89098
+ targetId: string().min(1),
89099
+ configured: boolean(),
89100
+ source: _enum(["native", "assigned"]),
89101
+ state: _enum([
89102
+ "active",
89103
+ "stale",
89104
+ "released",
89105
+ "unavailable"
89106
+ ]),
89107
+ reason: string().nullable()
89108
+ });
86226
89109
  var G711_SCALE_CORRECTION_DB = {
86227
89110
  PCMU: 20 * Math.log10(4),
86228
89111
  PCMA: 20 * Math.log10(8)
@@ -86275,40 +89158,7 @@ var NC_AUDIO_DEFAULTS = {
86275
89158
  samplingSeconds: 10
86276
89159
  };
86277
89160
  new Set(["devices", "classes"]);
86278
- /**
86279
- * WHICH narrowing filter speaks about WHICH system-event kind — one predicate,
86280
- * consumed by the rule ENGINE and by every rule EDITOR.
86281
- *
86282
- * ── The failure this file exists for ───────────────────────────────────────
86283
- * `NcSystemEventConditionSchema` carries four optional narrowing lists
86284
- * (`deviceIds`, `deviceTypes`, `nodeIds`, `packageNames`) beside a required
86285
- * `kinds` gate. They are not four filters over one vocabulary: each belongs to
86286
- * a FAMILY of kinds and is meaningless outside it. A node going away has no
86287
- * device type; a completed export has no package; `stream-offline` deliberately
86288
- * carries no device type at all (a stream belongs to a camera by construction).
86289
- *
86290
- * The engine applied all four to every kind, so a filter from one family failed
86291
- * a kind from another family CLOSED. The operator's live rule "Eventi di
86292
- * sistema" selected eleven kinds and set `deviceTypes: ['camera']` — the only
86293
- * way to say "only my cameras" about the two liveness kinds — and NINE of the
86294
- * eleven silently stopped being deliverable. Four days of history contained
86295
- * `device-online` and `device-offline` and nothing else, across a window in
86296
- * which agents were restarted and addons were updated.
86297
- *
86298
- * Both editors already computed this scoping, to decide which filter boxes to
86299
- * render; the cap's own docblock already promised it ("Narrow a `device-*` kind
86300
- * to these device TYPES"). Only the engine disagreed, and it disagreed in the
86301
- * destructive direction. So the rule is stated ONCE, here, and the engine and
86302
- * the editors are readers of it rather than three independent authors.
86303
- *
86304
- * ── The direction ─────────────────────────────────────────────────────────
86305
- * Out of family ⇒ the filter is IGNORED, never fail-closed. An editor that
86306
- * hides a box has already told the operator this filter does not speak about
86307
- * these kinds, so honouring it as an exclusion contradicts the only
86308
- * explanation the operator was ever given. Inside its family the filter still
86309
- * narrows, and still fails CLOSED on a subject that cannot produce the identity
86310
- * it tests (a device the mirror cannot name is not evidence of a camera).
86311
- */
89161
+ new Set(NC_LEGACY_SYSTEM_EVENT_KINDS);
86312
89162
  /**
86313
89163
  * Every filter, for the callers that must cover all of them (guards, tests).
86314
89164
  *
@@ -86334,9 +89184,6 @@ new Map(Object.entries({
86334
89184
  "device-battery-normal": "device-events",
86335
89185
  "device-consumable-low": "device-events",
86336
89186
  "device-consumable-normal": "device-events",
86337
- "device-tank-low": "device-events",
86338
- "device-tank-full": "device-events",
86339
- "device-tank-normal": "device-events",
86340
89187
  "stream-online": "device-events",
86341
89188
  "stream-offline": "device-events",
86342
89189
  "detection-blind": "device-events",
@@ -86413,16 +89260,6 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
86413
89260
  label: "Consumables",
86414
89261
  kinds: ["device-consumable-low", "device-consumable-normal"]
86415
89262
  },
86416
- {
86417
- id: "tanks",
86418
- family: "device-events",
86419
- label: "Tanks",
86420
- kinds: [
86421
- "device-tank-low",
86422
- "device-tank-full",
86423
- "device-tank-normal"
86424
- ]
86425
- },
86426
89263
  {
86427
89264
  id: "detection-blind",
86428
89265
  family: "device-events",
@@ -86580,11 +89417,6 @@ var RULE_BODY_ONLY = ["body"];
86580
89417
  var RULE_TEXT = ["title", "body"];
86581
89418
  var BATTERY = ["device-battery-low", "device-battery-normal"];
86582
89419
  var CONSUMABLE = ["device-consumable-low", "device-consumable-normal"];
86583
- var TANK = [
86584
- "device-tank-low",
86585
- "device-tank-full",
86586
- "device-tank-normal"
86587
- ];
86588
89420
  var ALERT_EPISODE = [
86589
89421
  "alert-critical",
86590
89422
  "alert-error",
@@ -86616,7 +89448,6 @@ var DEVICE_EVENTS = [
86616
89448
  "device-enabled",
86617
89449
  ...BATTERY,
86618
89450
  ...CONSUMABLE,
86619
- ...TANK,
86620
89451
  "stream-online",
86621
89452
  "stream-offline",
86622
89453
  "detection-blind",
@@ -86647,7 +89478,7 @@ var STATE_SUMMARY_SECTION_VARS = [
86647
89478
  {
86648
89479
  name: "summaryStreams",
86649
89480
  label: "Summary: streams offline",
86650
- example: "Ingresso (high) — since 06:40",
89481
+ example: "Front door (high) — since 06:40",
86651
89482
  kinds: ["stream-offline", "stream-online"]
86652
89483
  },
86653
89484
  {
@@ -86662,22 +89493,16 @@ var STATE_SUMMARY_SECTION_VARS = [
86662
89493
  example: "Robot — filter 10 %",
86663
89494
  kinds: CONSUMABLE
86664
89495
  },
86665
- {
86666
- name: "summaryTanks",
86667
- label: "Summary: tanks",
86668
- example: "Robot — clean water low",
86669
- kinds: TANK
86670
- },
86671
89496
  {
86672
89497
  name: "summaryDetection",
86673
89498
  label: "Summary: cameras detecting nothing",
86674
- example: "Ingresso — since 05:10",
89499
+ example: "Front door — since 05:10",
86675
89500
  kinds: ["detection-blind"]
86676
89501
  },
86677
89502
  {
86678
89503
  name: "summaryNodes",
86679
89504
  label: "Summary: nodes",
86680
- example: "little-unraid — offline since 03:00",
89505
+ example: "agent-a — offline since 03:00",
86681
89506
  kinds: [
86682
89507
  "node-offline",
86683
89508
  "node-online",
@@ -86783,8 +89608,7 @@ var STATE_SUMMARY_VARS = [
86783
89608
  ([...RULE_TEXT], [...COMBINED_ALARM]),
86784
89609
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
86785
89610
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
86786
- ([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
86787
- ([...RULE_TEXT], [...TANK]),
89611
+ ([...RULE_TEXT], [...CONSUMABLE]),
86788
89612
  [...RULE_TEXT],
86789
89613
  ([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
86790
89614
  ([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
@@ -86888,15 +89712,6 @@ new Map([
86888
89712
  snapshotLabel: "Consumables low now",
86889
89713
  snapshotSection: "consumables"
86890
89714
  },
86891
- {
86892
- id: "tanks",
86893
- family: "device-events",
86894
- label: "Tanks (low or full / back to normal)",
86895
- bad: ["device-tank-low", "device-tank-full"],
86896
- recovery: ["device-tank-normal"],
86897
- snapshotLabel: "Tanks low or full now",
86898
- snapshotSection: "tanks"
86899
- },
86900
89715
  {
86901
89716
  id: "motion-noise",
86902
89717
  family: "device-events",
@@ -87349,6 +90164,10 @@ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
87349
90164
  function providerMotionEvent(source, data) {
87350
90165
  return createEvent(EventCategory.ProviderMotion, source, data);
87351
90166
  }
90167
+ Object.freeze({
90168
+ person: .8,
90169
+ vehicle: .8
90170
+ });
87352
90171
  object({
87353
90172
  /**
87354
90173
  * Fraction of the box's own size added on EACH side before cutting.
@@ -188579,7 +191398,7 @@ var REOLINK_ADDON_ID = "provider-reolink";
188579
191398
  * TWO vocabularies arrive here and both must be keyed. The simple-event push
188580
191399
  * (cmd 33 `<AItype>`) says `animal`; the capability probe (cmd 299
188581
191400
  * `getAiDetectTypes`) says `dog_cat` for the same class. Keying only the first
188582
- * made `buildSupportedClasses` drop it, so camera 618 reported
191401
+ * made `buildSupportedClasses` drop it, so camera 108 reported
188583
191402
  * `supportedClasses: ["person","vehicle"]` while its own `lastByClass` held a
188584
191403
  * live `animal` detection — the camera detected a class the system said it
188585
191404
  * could not. The two key-spaces do not collide, so one map serves both.
@@ -188664,7 +191483,7 @@ var reolinkCameraSchema = object({
188664
191483
  *
188665
191484
  * Empty = nothing configured, and `goHome` then REFUSES. It used to go to a
188666
191485
  * hardcoded slot on a vendor "convention" this fleet contradicts: reolink
188667
- * went to preset 0, which on device 592 holds "stanza"; amcrest went to
191486
+ * went to preset 0, which on device 107 holds "stanza"; amcrest went to
188668
191487
  * preset 1, which on device 3836 holds "Preset1". Both swallowed the failure
188669
191488
  * in a bare catch, so a head that never moved was indistinguishable from a
188670
191489
  * head that went home.
@@ -189583,7 +192402,7 @@ var UID_MISSING_REASON = "uid-missing: the hub selects a child by uid, and this
189583
192402
  *
189584
192403
  * - a **closed day** cannot gain or lose a recording, so its listing is
189585
192404
  * immutable for {@link CLOSED_DAY_TTL_MS}. Re-listing yesterday on every
189586
- * scroll would cost 2.0 s of camera time (measured: 546 clips on 592) for an
192405
+ * scroll would cost 2.0 s of camera time (measured: 546 clips on 107) for an
189587
192406
  * answer that cannot have changed;
189588
192407
  * - **today** is `serve-and-revalidate` under `OPERATOR_WRITTEN_STALE_MS` —
189589
192408
  * the same discipline every other Reolink read uses (D224), for the same
@@ -194333,7 +197152,7 @@ function buildClipRefreshDeviceSection(input) {
194333
197152
  *
194334
197153
  * `failure-contribution` keeps `variant` for a second dimension WITHIN a
194335
197154
  * family, and here the useful one is the format the caller pushed: an operator
194336
- * asking "why is 617 silent" needs to know whether HomeKit's Opus or Alexa's
197155
+ * asking "why is 102 silent" needs to know whether HomeKit's Opus or Alexa's
194337
197156
  * raw PCM is the half that is failing. The provider is handed that value on
194338
197157
  * every call, so it is reported rather than guessed — absent, never invented.
194339
197158
  *
@@ -195677,7 +198496,7 @@ async function refreshSnapshotCacheOnce(input) {
195677
198496
  * `logger.child(stableId).withTags({ deviceId })` with the NUMERIC id
195678
198497
  * (`device-cap-proxy.ts`), and `ScopedLogger` merges its bound tags into every
195679
198498
  * line. So every line these channels admit carries `tags.deviceId`, and
195680
- * `| json | deviceId="617"` selects exactly one camera. That is the repo rule
198499
+ * `| json | deviceId="102"` selects exactly one camera. That is the repo rule
195681
198500
  * from `CLAUDE.md` — paid for with a 22% thumbnail gap and a 3-hour media
195682
198501
  * blackout diagnosed by hand — finally paying out.
195683
198502
  *
@@ -195781,7 +198600,7 @@ function capDayNightModeToReolink(mode) {
195781
198600
  * `battery-operated` is derived from the probe flag **OR** the driver's own
195782
198601
  * `isBattery` discriminator — never the probe alone. The probe slice is
195783
198602
  * written only by a SUCCESSFUL `feature-probe` round-trip, and a battery
195784
- * camera that is asleep (or flat, or off-LAN) never answers one: device 640
198603
+ * camera that is asleep (or flat, or off-LAN) never answers one: device 106
195785
198604
  * "Baby monitor" held `deviceCache.deviceType === 'battery-cam'`, a
195786
198605
  * `battery` runtime slice reporting `sleeping: true`, and STILL published
195787
198606
  * `features = ['native-snapshot','rebootable']` because the `feature-probe`
@@ -195792,7 +198611,7 @@ function capDayNightModeToReolink(mode) {
195792
198611
  * map) — without it the camera is drawn as an ordinary awake camera;
195793
198612
  * - the snapshot wrapper's sleep gate (`snapshot.addon.ts`
195794
198613
  * `lookupDeviceMeta().isBattery`) — without it every thumbnail refresh
195795
- * issues a Baichuan login and WAKES the camera (observed hourly on 640
198614
+ * issues a Baichuan login and WAKES the camera (observed hourly on 106
195796
198615
  * while it sat at 14%);
195797
198616
  * - the broker's `preBufferSec = 0` battery rule and its relaxed stall
195798
198617
  * watchdog.
@@ -198855,7 +201674,7 @@ function isNativeObjectForwardingEnabled(capState) {
198855
201674
  * closure inside `registerNativeObjectDetectionCap` had a test that
198856
201675
  * RE-IMPLEMENTED it — and the copy encoded the `dog_cat` gap as intent
198857
201676
  * ("skips unknown Baichuan type names"), so the suite stayed green while
198858
- * camera 618 reported it could not detect a class it was detecting. One
201677
+ * camera 108 reported it could not detect a class it was detecting. One
198859
201678
  * function, one test, no copy.
198860
201679
  *
198861
201680
  * An absent probe is not an empty answer: it means nobody has asked the camera
@@ -199717,7 +202536,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
199717
202536
  * dispatched N times on the camstack side, and `offSimpleEvent`
199718
202537
  * couldn't remove the old one without the original ref. Net
199719
202538
  * effect was that subscriptions drifted out of sync with the
199720
- * camera's TCP push channel: device 15 (Daniel) went silent for
202539
+ * camera's TCP push channel: device 15 (Carol) went silent for
199721
202540
  * 2+ hours while device 8 (battery doorbell) kept pushing
199722
202541
  * normally because its short connection lifecycle naturally
199723
202542
  * reset the listener set.
@@ -200737,7 +203556,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
200737
203556
  }
200738
203557
  /**
200739
203558
  * Arm Baichuan HaCfg (cmd 807) so this battery camera POSTs wake/sleep
200740
- * events to the provider's HTTP intake. Mirrors Scrypted's
203559
+ * events to the provider's HTTP intake. Mirrors plugin catalog's
200741
203560
  * `autoConfigureBaichuanWebhook` — never called from init.
200742
203561
  */
200743
203562
  async autoConfigureBaichuanWebhook() {
@@ -204194,7 +207013,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
204194
207013
  /**
204195
207014
  * Synthesize the HTTP-FLV pull URL for a (channel, profile) pair. FLV is
204196
207015
  * served off the Reolink Baichuan media port (default 1935, app `bcs`) as
204197
- * `channel<channel>_<profile>.bcs` — the same shape go2rtc uses. The
207016
+ * `channel<channel>_<profile>.bcs` — the same shape restreamer uses. The
204198
207017
  * lib does NOT surface this URL, so we build it from the SAME connection
204199
207018
  * creds the RTSP/native paths use (`host`/`username`/`password` on the
204200
207019
  * device config), URL-encoding the credentials.