@camstack/addon-provider-homeassistant 1.2.35 → 1.2.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/addon.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("./dist-DCvHGfFW.js");
2
+ const require_dist = require("./dist-Cnf3N7Ug.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  let node_zlib = require("node:zlib");
5
5
  //#region src/ha-device-source.ts
package/dist/addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as pressureSensorCapability, A as coverCapability, B as imageCapability, C as buttonCapability, Ct as record, D as connectivityCapability, Dt as url, E as colorCapability, Et as unknown, F as fanControlCapability, G as normalizeUnit, H as lockControlCapability, I as floodCapability, J as numericSensorCapability, K as notificationOutputCapability, L as gasCapability, N as enumSensorCapability, O as contactCapability, Ot as EventCategory, P as eventEmitterCapability, Q as presenceCapability, R as humidifierCapability, S as buildAddonRouteProvider, St as object, T as climateControlCapability, Tt as union, U as mediaPlayerCapability, V as lawnMowerControlCapability, W as motionCapability, X as powerMeterCapability, Z as prepareNotification, _ as batteryCapability, _t as _enum, at as updateCapability, b as brightnessCapability, bt as literal, ct as vibrationCapability, d as accessoriesCapability, dt as errMsg, et as scriptRunnerCapability, f as addonRoutesCapability, g as automationControlCapability, gt as createEvent, h as ambientLightSensorCapability, ht as DeviceType, it as temperatureSensorCapability, j as deviceAdoptionCapability, k as controlCapability, lt as waterHeaterCapability, m as alarmPanelCapability, mt as DeviceRole, n as BaseDevice, nt as switchCapability, o as EnumSensorDateTimeFormatSchema, ot as vacuumControlCapability, p as airQualitySensorCapability, pt as DeviceFeature, q as notifierCapability, r as BaseDeviceProvider, rt as tamperCapability, st as valveCapability, tt as smokeCapability, u as TargetSchema, ut as weatherCapability, v as bestLocationMatch, vt as array, w as carbonMonoxideCapability, wt as string, x as brokerCapability, xt as number, y as binaryCapability, yt as discriminatedUnion, z as humiditySensorCapability } from "./dist-DObg5VV6.mjs";
1
+ import { $ as pressureSensorCapability, A as coverCapability, B as imageCapability, C as buttonCapability, Ct as record, D as connectivityCapability, Dt as url, E as colorCapability, Et as unknown, F as fanControlCapability, G as normalizeUnit, H as lockControlCapability, I as floodCapability, J as numericSensorCapability, K as notificationOutputCapability, L as gasCapability, N as enumSensorCapability, O as contactCapability, Ot as EventCategory, P as eventEmitterCapability, Q as presenceCapability, R as humidifierCapability, S as buildAddonRouteProvider, St as object, T as climateControlCapability, Tt as union, U as mediaPlayerCapability, V as lawnMowerControlCapability, W as motionCapability, X as powerMeterCapability, Z as prepareNotification, _ as batteryCapability, _t as _enum, at as updateCapability, b as brightnessCapability, bt as literal, ct as vibrationCapability, d as accessoriesCapability, dt as errMsg, et as scriptRunnerCapability, f as addonRoutesCapability, g as automationControlCapability, gt as createEvent, h as ambientLightSensorCapability, ht as DeviceType, it as temperatureSensorCapability, j as deviceAdoptionCapability, k as controlCapability, lt as waterHeaterCapability, m as alarmPanelCapability, mt as DeviceRole, n as BaseDevice, nt as switchCapability, o as EnumSensorDateTimeFormatSchema, ot as vacuumControlCapability, p as airQualitySensorCapability, pt as DeviceFeature, q as notifierCapability, r as BaseDeviceProvider, rt as tamperCapability, st as valveCapability, tt as smokeCapability, u as TargetSchema, ut as weatherCapability, v as bestLocationMatch, vt as array, w as carbonMonoxideCapability, wt as string, x as brokerCapability, xt as number, y as binaryCapability, yt as discriminatedUnion, z as humiditySensorCapability } from "./dist-CZfScvEk.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
4
4
  //#region src/ha-device-source.ts
@@ -7684,7 +7684,7 @@ var RecordingBandSchema = object({
7684
7684
  postBufferSec: number().min(0).optional()
7685
7685
  });
7686
7686
  ({
7687
- preBufferSec: 10,
7687
+ preBufferSec: 15,
7688
7688
  postBufferSec: 30
7689
7689
  }).postBufferSec * 1e3;
7690
7690
  /**
@@ -14056,128 +14056,103 @@ var COCO_TO_MACRO = {
14056
14056
  var AUDIO_MACRO_LABELS = [
14057
14057
  {
14058
14058
  id: "speech",
14059
- name: "Speech",
14060
- icon: "🗣️"
14059
+ name: "Speech"
14061
14060
  },
14062
14061
  {
14063
14062
  id: "scream",
14064
- name: "Scream / Shout",
14065
- icon: "😱"
14063
+ name: "Scream / Shout"
14066
14064
  },
14067
14065
  {
14068
14066
  id: "crying",
14069
- name: "Crying / Baby",
14070
- icon: "😢"
14067
+ name: "Crying / Baby"
14071
14068
  },
14072
14069
  {
14073
14070
  id: "laughter",
14074
- name: "Laughter",
14075
- icon: "😂"
14071
+ name: "Laughter"
14076
14072
  },
14077
14073
  {
14078
14074
  id: "music",
14079
- name: "Music",
14080
- icon: "🎵"
14075
+ name: "Music"
14081
14076
  },
14082
14077
  {
14083
14078
  id: "dog",
14084
- name: "Dog",
14085
- icon: "🐕"
14079
+ name: "Dog"
14086
14080
  },
14087
14081
  {
14088
14082
  id: "cat",
14089
- name: "Cat",
14090
- icon: "🐈"
14083
+ name: "Cat"
14091
14084
  },
14092
14085
  {
14093
14086
  id: "bird",
14094
- name: "Bird",
14095
- icon: "🐦"
14087
+ name: "Bird"
14096
14088
  },
14097
14089
  {
14098
14090
  id: "animal",
14099
- name: "Animal (other)",
14100
- icon: "🐾"
14091
+ name: "Animal (other)"
14101
14092
  },
14102
14093
  {
14103
14094
  id: "alarm",
14104
- name: "Alarm / Siren",
14105
- icon: "🚨"
14095
+ name: "Alarm / Siren"
14106
14096
  },
14107
14097
  {
14108
14098
  id: "doorbell",
14109
- name: "Doorbell / Knock",
14110
- icon: "🔔"
14099
+ name: "Doorbell / Knock"
14111
14100
  },
14112
14101
  {
14113
14102
  id: "glass_breaking",
14114
- name: "Glass Breaking",
14115
- icon: "💥"
14103
+ name: "Glass Breaking"
14116
14104
  },
14117
14105
  {
14118
14106
  id: "gunshot",
14119
- name: "Gunshot / Explosion",
14120
- icon: "💣"
14107
+ name: "Gunshot / Explosion"
14121
14108
  },
14122
14109
  {
14123
14110
  id: "vehicle",
14124
- name: "Vehicle",
14125
- icon: "🚗"
14111
+ name: "Vehicle"
14126
14112
  },
14127
14113
  {
14128
14114
  id: "siren",
14129
- name: "Emergency Siren",
14130
- icon: "🚑"
14115
+ name: "Emergency Siren"
14131
14116
  },
14132
14117
  {
14133
14118
  id: "fire",
14134
- name: "Fire / Smoke",
14135
- icon: "🔥"
14119
+ name: "Fire / Smoke"
14136
14120
  },
14137
14121
  {
14138
14122
  id: "water",
14139
- name: "Water",
14140
- icon: "💧"
14123
+ name: "Water"
14141
14124
  },
14142
14125
  {
14143
14126
  id: "wind",
14144
- name: "Wind / Weather",
14145
- icon: "🌬️"
14127
+ name: "Wind / Weather"
14146
14128
  },
14147
14129
  {
14148
14130
  id: "door",
14149
- name: "Door",
14150
- icon: "🚪"
14131
+ name: "Door"
14151
14132
  },
14152
14133
  {
14153
14134
  id: "footsteps",
14154
- name: "Footsteps",
14155
- icon: "👣"
14135
+ name: "Footsteps"
14156
14136
  },
14157
14137
  {
14158
14138
  id: "crowd",
14159
- name: "Crowd / Chatter",
14160
- icon: "👥"
14139
+ name: "Crowd / Chatter"
14161
14140
  },
14162
14141
  {
14163
14142
  id: "telephone",
14164
- name: "Telephone",
14165
- icon: "📞"
14143
+ name: "Telephone"
14166
14144
  },
14167
14145
  {
14168
14146
  id: "engine",
14169
- name: "Engine / Motor",
14170
- icon: "⚙️"
14147
+ name: "Engine / Motor"
14171
14148
  },
14172
14149
  {
14173
14150
  id: "tools",
14174
- name: "Tools / Construction",
14175
- icon: "🔨"
14151
+ name: "Tools / Construction"
14176
14152
  },
14177
14153
  {
14178
14154
  id: "silence",
14179
- name: "Silence",
14180
- icon: "🤫"
14155
+ name: "Silence"
14181
14156
  }
14182
14157
  ];
14183
14158
  var YAMNET_TO_MACRO = {
@@ -16685,7 +16660,7 @@ var TrackEnvelopeSchema = object({
16685
16660
  * `snapshots[]` references — megabytes across a page of tracks. `slim`
16686
16661
  * keeps every scalar the list surfaces actually render (ids, class(es),
16687
16662
  * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16688
- * zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
16663
+ * zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
16689
16664
  * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16690
16665
  * `getTrack`. Mirrors the event-store `projection` convention
16691
16666
  * (`getObjectEvents` et al.).
@@ -16980,6 +16955,35 @@ var TrackSchema = object({
16980
16955
  */
16981
16956
  hasFace: boolean().optional(),
16982
16957
  /**
16958
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding — a
16959
+ * face an operator could ASSIGN to an identity.
16960
+ *
16961
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
16962
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
16963
+ * branch, before every gate, and means no more than "a face detector produced
16964
+ * a face detail". This one is stamped at the single moment the gallery row
16965
+ * LANDS — after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
16966
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
16967
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
16968
+ * the crop-store drop. Everything between the detector and that insert can
16969
+ * legitimately refuse the face, so a flag written any earlier promises the
16970
+ * operator something to assign and delivers nothing.
16971
+ *
16972
+ * **Independent of recognition.** A face collected but never auto-matched is
16973
+ * still assignable — it is in fact the face an operator most wants to reach —
16974
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
16975
+ * `subLabel`; this says only that the raw material exists.
16976
+ *
16977
+ * **Set once, never cleared.** A track that produced a gallery row produced
16978
+ * one; deleting the row later is the gallery's business, not this flag's.
16979
+ *
16980
+ * **Absent ≠ false**, the same rule as {@link hasFace}: every row written
16981
+ * before the column omits it, and so does every server that predates the
16982
+ * field. A consumer must test `=== true` and render nothing otherwise —
16983
+ * never infer "no assignable face".
16984
+ */
16985
+ hasEmbeddedFace: boolean().optional(),
16986
+ /**
16983
16987
  * This subject CONTAINS a folded rider — a person the rider-pairing step
16984
16988
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
16985
16989
  * so the passage is tracked once and as a VEHICLE.
@@ -18369,6 +18373,32 @@ var DetailResultSchema = object({
18369
18373
  /** FRAME-space bbox (already mapped back from crop space). */
18370
18374
  bbox: NativeCropBboxSchema.optional(),
18371
18375
  embedding: string().optional(),
18376
+ /**
18377
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
18378
+ * so an older runner that does not send it degrades to "unmeasurable", which
18379
+ * the consuming gate treats as accept — never as reject.
18380
+ */
18381
+ embeddingMagnitude: number().optional(),
18382
+ /**
18383
+ * Model that produced `embedding` — the SAME contract `labelModelId` has for
18384
+ * `label`, and for the same reason: the producing node is the only side that
18385
+ * knows which model actually ran, and re-deriving it downstream is exactly
18386
+ * the inference this model exists to forbid.
18387
+ *
18388
+ * Additive and optional, so a runner that predates it degrades to
18389
+ * "unmeasurable" rather than to a wrong answer — the consumer falls back to
18390
+ * its previous assumption instead of refusing.
18391
+ *
18392
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
18393
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
18394
+ * with nothing on the wire it took the id from the GALLERY, so the gate
18395
+ * compared the gallery against itself and could never fire. That turned the
18396
+ * one guard protecting the face feature space into a tautology, and it is
18397
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
18398
+ * gallery as the catalog comment predicts — it would have scored the new
18399
+ * model's vectors against the old model's samples in one cosine space.
18400
+ */
18401
+ embeddingModelId: string().optional(),
18372
18402
  label: string().optional(),
18373
18403
  /**
18374
18404
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -19779,6 +19809,7 @@ DeviceType.Camera, method(object({
19779
19809
  isBattery: boolean(),
19780
19810
  reason: _enum([
19781
19811
  "disabled",
19812
+ "offline",
19782
19813
  "sleeping",
19783
19814
  "unreachable",
19784
19815
  "waking"
@@ -19824,9 +19855,17 @@ targets: array(object({
19824
19855
  sleeping: boolean(),
19825
19856
  /** Current device state rendered over the cached frame. State images
19826
19857
  * remain authoritative even when their photographic background is
19827
- * old; null means the link must carry a current camera frame. */
19858
+ * old; null means the link must carry a current camera frame.
19859
+ *
19860
+ * **This is the ONLY source a surface may derive an inactive tile
19861
+ * from.** A client that reads a device's `online`/`disabled` flags and
19862
+ * draws its own verdict will disagree with the pixels it is painting
19863
+ * — the frame comes from here, and so must the sentence over it
19864
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
19865
+ * state. */
19828
19866
  stateReason: _enum([
19829
19867
  "disabled",
19868
+ "offline",
19830
19869
  "sleeping",
19831
19870
  "unreachable",
19832
19871
  "waking"
@@ -26634,9 +26673,21 @@ var RecordingLocationUsageSchema = object({
26634
26673
  * previously rendered as two identical "disks" with a nonsensical used
26635
26674
  * split — hydrate attribution across aliases is arbitrary by nature. */
26636
26675
  locationIds: array(string()).optional(),
26637
- /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
26676
+ /**
26677
+ * Filesystem root of the physical volume this row accounts — the only
26678
+ * operator-legible identity when a location has no `displayName` yet, and
26679
+ * what a "which disk is full" alert has to name. OPTIONAL for the same
26680
+ * train-skew reason as `oldestMs`: a recorder that predates the field omits
26681
+ * it, and this schema must keep validating that older provider's payload.
26682
+ */
26683
+ root: string().optional(),
26684
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
26685
+ * the footage's SHARE of the volume, not how full the volume is — the disk
26686
+ * also holds everything that is not recordings. Volume fill is
26687
+ * `(totalBytes - availableBytes) / totalBytes`. */
26638
26688
  usedBytes: number(),
26639
- /** Free bytes on the location's volume; null when capacity is unknown (remote). */
26689
+ /** Free bytes on the location's volume; null when capacity is unknown
26690
+ * (remote/unstattable — the recorder logs the statfs failure with the root). */
26640
26691
  availableBytes: number().nullable(),
26641
26692
  /** Total bytes of the location's volume; null when unknown. */
26642
26693
  totalBytes: number().nullable()
@@ -26648,7 +26699,15 @@ var RecordingStorageUsageSchema = object({
26648
26699
  nodeId: string(),
26649
26700
  totalUsedBytes: number(),
26650
26701
  devices: array(RecordingDeviceUsageSchema),
26651
- locations: array(RecordingLocationUsageSchema)
26702
+ /**
26703
+ * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
26704
+ * of the payload without it: the hub serves this method through a BAKED
26705
+ * router, so a hub whose framework train predates a change to this array
26706
+ * strips it out of an answer a newer recorder happily produced. A UI that
26707
+ * dereferences it unconditionally crashes the whole Storage page over a
26708
+ * missing disk bar.
26709
+ */
26710
+ locations: array(RecordingLocationUsageSchema).optional()
26652
26711
  });
26653
26712
  /**
26654
26713
  * The OPERATOR-ARMED half of multi-location recordings (D116).
@@ -37433,7 +37492,11 @@ Object.freeze({
37433
37492
  "network-access": "ingress",
37434
37493
  "smtp-provider": "email"
37435
37494
  });
37436
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
37495
+ /** Schema defaults an untouched sub-field must author exactly these. */
37496
+ var NC_AUDIO_DEFAULTS = {
37497
+ hitPercent: 60,
37498
+ samplingSeconds: 10
37499
+ };
37437
37500
  new Set(["devices", "classes"]);
37438
37501
  /** Strip a small, safe subset of Markdown down to plain text. */
37439
37502
  function markdownToText(md) {
@@ -37642,6 +37705,7 @@ function prepareNotification(caps, n) {
37642
37705
  renderedAs
37643
37706
  };
37644
37707
  }
37708
+ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
37645
37709
  /**
37646
37710
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
37647
37711
  *
@@ -37873,6 +37937,39 @@ TimelapseRuleInputSchema.extend({
37873
37937
  createdAt: number(),
37874
37938
  updatedAt: number()
37875
37939
  });
37940
+ Object.freeze(Object.fromEntries([{
37941
+ stepId: "face-embedding",
37942
+ label: "Face recognition model",
37943
+ defaultModelId: "arcface-r100",
37944
+ indexName: "the enrolled face gallery",
37945
+ options: [
37946
+ {
37947
+ id: "arcface-r100",
37948
+ label: "ArcFace (ResNet34)"
37949
+ },
37950
+ {
37951
+ id: "auraface-r100",
37952
+ label: "AuraFace R100"
37953
+ },
37954
+ {
37955
+ id: "inception-resnet-v1",
37956
+ label: "Inception ResNet V1"
37957
+ }
37958
+ ]
37959
+ }, {
37960
+ stepId: "clip-embedding",
37961
+ label: "Semantic search model",
37962
+ defaultModelId: "mobileclip-s1",
37963
+ indexName: "the object semantic-search index",
37964
+ options: [{
37965
+ id: "mobileclip-s1",
37966
+ label: "MobileCLIP S1"
37967
+ }, {
37968
+ id: "mobileclip-s2",
37969
+ label: "MobileCLIP S2"
37970
+ }]
37971
+ }].map((s) => [s.stepId, s.defaultModelId])));
37972
+ string().min(1);
37876
37973
  object({
37877
37974
  /**
37878
37975
  * Fraction of the box's own size added on EACH side before cutting.
@@ -37893,10 +37990,21 @@ object({
37893
37990
  */
37894
37991
  square: boolean()
37895
37992
  });
37896
- ({
37993
+ /**
37994
+ * The convention in force when nobody has configured one — byte-for-byte the
37995
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
37996
+ */
37997
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
37897
37998
  paddingRatio: .15,
37898
37999
  square: false
37899
- }).paddingRatio;
38000
+ };
38001
+ Object.freeze({
38002
+ x: 0,
38003
+ y: 0,
38004
+ w: 1,
38005
+ h: 1
38006
+ });
38007
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
37900
38008
  /**
37901
38009
  * WHICH delivered frames the decode worker retains a native copy of.
37902
38010
  *
@@ -7684,7 +7684,7 @@ var RecordingBandSchema = object({
7684
7684
  postBufferSec: number().min(0).optional()
7685
7685
  });
7686
7686
  ({
7687
- preBufferSec: 10,
7687
+ preBufferSec: 15,
7688
7688
  postBufferSec: 30
7689
7689
  }).postBufferSec * 1e3;
7690
7690
  /**
@@ -14056,128 +14056,103 @@ var COCO_TO_MACRO = {
14056
14056
  var AUDIO_MACRO_LABELS = [
14057
14057
  {
14058
14058
  id: "speech",
14059
- name: "Speech",
14060
- icon: "🗣️"
14059
+ name: "Speech"
14061
14060
  },
14062
14061
  {
14063
14062
  id: "scream",
14064
- name: "Scream / Shout",
14065
- icon: "😱"
14063
+ name: "Scream / Shout"
14066
14064
  },
14067
14065
  {
14068
14066
  id: "crying",
14069
- name: "Crying / Baby",
14070
- icon: "😢"
14067
+ name: "Crying / Baby"
14071
14068
  },
14072
14069
  {
14073
14070
  id: "laughter",
14074
- name: "Laughter",
14075
- icon: "😂"
14071
+ name: "Laughter"
14076
14072
  },
14077
14073
  {
14078
14074
  id: "music",
14079
- name: "Music",
14080
- icon: "🎵"
14075
+ name: "Music"
14081
14076
  },
14082
14077
  {
14083
14078
  id: "dog",
14084
- name: "Dog",
14085
- icon: "🐕"
14079
+ name: "Dog"
14086
14080
  },
14087
14081
  {
14088
14082
  id: "cat",
14089
- name: "Cat",
14090
- icon: "🐈"
14083
+ name: "Cat"
14091
14084
  },
14092
14085
  {
14093
14086
  id: "bird",
14094
- name: "Bird",
14095
- icon: "🐦"
14087
+ name: "Bird"
14096
14088
  },
14097
14089
  {
14098
14090
  id: "animal",
14099
- name: "Animal (other)",
14100
- icon: "🐾"
14091
+ name: "Animal (other)"
14101
14092
  },
14102
14093
  {
14103
14094
  id: "alarm",
14104
- name: "Alarm / Siren",
14105
- icon: "🚨"
14095
+ name: "Alarm / Siren"
14106
14096
  },
14107
14097
  {
14108
14098
  id: "doorbell",
14109
- name: "Doorbell / Knock",
14110
- icon: "🔔"
14099
+ name: "Doorbell / Knock"
14111
14100
  },
14112
14101
  {
14113
14102
  id: "glass_breaking",
14114
- name: "Glass Breaking",
14115
- icon: "💥"
14103
+ name: "Glass Breaking"
14116
14104
  },
14117
14105
  {
14118
14106
  id: "gunshot",
14119
- name: "Gunshot / Explosion",
14120
- icon: "💣"
14107
+ name: "Gunshot / Explosion"
14121
14108
  },
14122
14109
  {
14123
14110
  id: "vehicle",
14124
- name: "Vehicle",
14125
- icon: "🚗"
14111
+ name: "Vehicle"
14126
14112
  },
14127
14113
  {
14128
14114
  id: "siren",
14129
- name: "Emergency Siren",
14130
- icon: "🚑"
14115
+ name: "Emergency Siren"
14131
14116
  },
14132
14117
  {
14133
14118
  id: "fire",
14134
- name: "Fire / Smoke",
14135
- icon: "🔥"
14119
+ name: "Fire / Smoke"
14136
14120
  },
14137
14121
  {
14138
14122
  id: "water",
14139
- name: "Water",
14140
- icon: "💧"
14123
+ name: "Water"
14141
14124
  },
14142
14125
  {
14143
14126
  id: "wind",
14144
- name: "Wind / Weather",
14145
- icon: "🌬️"
14127
+ name: "Wind / Weather"
14146
14128
  },
14147
14129
  {
14148
14130
  id: "door",
14149
- name: "Door",
14150
- icon: "🚪"
14131
+ name: "Door"
14151
14132
  },
14152
14133
  {
14153
14134
  id: "footsteps",
14154
- name: "Footsteps",
14155
- icon: "👣"
14135
+ name: "Footsteps"
14156
14136
  },
14157
14137
  {
14158
14138
  id: "crowd",
14159
- name: "Crowd / Chatter",
14160
- icon: "👥"
14139
+ name: "Crowd / Chatter"
14161
14140
  },
14162
14141
  {
14163
14142
  id: "telephone",
14164
- name: "Telephone",
14165
- icon: "📞"
14143
+ name: "Telephone"
14166
14144
  },
14167
14145
  {
14168
14146
  id: "engine",
14169
- name: "Engine / Motor",
14170
- icon: "⚙️"
14147
+ name: "Engine / Motor"
14171
14148
  },
14172
14149
  {
14173
14150
  id: "tools",
14174
- name: "Tools / Construction",
14175
- icon: "🔨"
14151
+ name: "Tools / Construction"
14176
14152
  },
14177
14153
  {
14178
14154
  id: "silence",
14179
- name: "Silence",
14180
- icon: "🤫"
14155
+ name: "Silence"
14181
14156
  }
14182
14157
  ];
14183
14158
  var YAMNET_TO_MACRO = {
@@ -16685,7 +16660,7 @@ var TrackEnvelopeSchema = object({
16685
16660
  * `snapshots[]` references — megabytes across a page of tracks. `slim`
16686
16661
  * keeps every scalar the list surfaces actually render (ids, class(es),
16687
16662
  * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16688
- * zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
16663
+ * zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
16689
16664
  * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16690
16665
  * `getTrack`. Mirrors the event-store `projection` convention
16691
16666
  * (`getObjectEvents` et al.).
@@ -16980,6 +16955,35 @@ var TrackSchema = object({
16980
16955
  */
16981
16956
  hasFace: boolean().optional(),
16982
16957
  /**
16958
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding — a
16959
+ * face an operator could ASSIGN to an identity.
16960
+ *
16961
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
16962
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
16963
+ * branch, before every gate, and means no more than "a face detector produced
16964
+ * a face detail". This one is stamped at the single moment the gallery row
16965
+ * LANDS — after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
16966
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
16967
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
16968
+ * the crop-store drop. Everything between the detector and that insert can
16969
+ * legitimately refuse the face, so a flag written any earlier promises the
16970
+ * operator something to assign and delivers nothing.
16971
+ *
16972
+ * **Independent of recognition.** A face collected but never auto-matched is
16973
+ * still assignable — it is in fact the face an operator most wants to reach —
16974
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
16975
+ * `subLabel`; this says only that the raw material exists.
16976
+ *
16977
+ * **Set once, never cleared.** A track that produced a gallery row produced
16978
+ * one; deleting the row later is the gallery's business, not this flag's.
16979
+ *
16980
+ * **Absent ≠ false**, the same rule as {@link hasFace}: every row written
16981
+ * before the column omits it, and so does every server that predates the
16982
+ * field. A consumer must test `=== true` and render nothing otherwise —
16983
+ * never infer "no assignable face".
16984
+ */
16985
+ hasEmbeddedFace: boolean().optional(),
16986
+ /**
16983
16987
  * This subject CONTAINS a folded rider — a person the rider-pairing step
16984
16988
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
16985
16989
  * so the passage is tracked once and as a VEHICLE.
@@ -18369,6 +18373,32 @@ var DetailResultSchema = object({
18369
18373
  /** FRAME-space bbox (already mapped back from crop space). */
18370
18374
  bbox: NativeCropBboxSchema.optional(),
18371
18375
  embedding: string().optional(),
18376
+ /**
18377
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
18378
+ * so an older runner that does not send it degrades to "unmeasurable", which
18379
+ * the consuming gate treats as accept — never as reject.
18380
+ */
18381
+ embeddingMagnitude: number().optional(),
18382
+ /**
18383
+ * Model that produced `embedding` — the SAME contract `labelModelId` has for
18384
+ * `label`, and for the same reason: the producing node is the only side that
18385
+ * knows which model actually ran, and re-deriving it downstream is exactly
18386
+ * the inference this model exists to forbid.
18387
+ *
18388
+ * Additive and optional, so a runner that predates it degrades to
18389
+ * "unmeasurable" rather than to a wrong answer — the consumer falls back to
18390
+ * its previous assumption instead of refusing.
18391
+ *
18392
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
18393
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
18394
+ * with nothing on the wire it took the id from the GALLERY, so the gate
18395
+ * compared the gallery against itself and could never fire. That turned the
18396
+ * one guard protecting the face feature space into a tautology, and it is
18397
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
18398
+ * gallery as the catalog comment predicts — it would have scored the new
18399
+ * model's vectors against the old model's samples in one cosine space.
18400
+ */
18401
+ embeddingModelId: string().optional(),
18372
18402
  label: string().optional(),
18373
18403
  /**
18374
18404
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -19779,6 +19809,7 @@ DeviceType.Camera, method(object({
19779
19809
  isBattery: boolean(),
19780
19810
  reason: _enum([
19781
19811
  "disabled",
19812
+ "offline",
19782
19813
  "sleeping",
19783
19814
  "unreachable",
19784
19815
  "waking"
@@ -19824,9 +19855,17 @@ targets: array(object({
19824
19855
  sleeping: boolean(),
19825
19856
  /** Current device state rendered over the cached frame. State images
19826
19857
  * remain authoritative even when their photographic background is
19827
- * old; null means the link must carry a current camera frame. */
19858
+ * old; null means the link must carry a current camera frame.
19859
+ *
19860
+ * **This is the ONLY source a surface may derive an inactive tile
19861
+ * from.** A client that reads a device's `online`/`disabled` flags and
19862
+ * draws its own verdict will disagree with the pixels it is painting
19863
+ * — the frame comes from here, and so must the sentence over it
19864
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
19865
+ * state. */
19828
19866
  stateReason: _enum([
19829
19867
  "disabled",
19868
+ "offline",
19830
19869
  "sleeping",
19831
19870
  "unreachable",
19832
19871
  "waking"
@@ -26634,9 +26673,21 @@ var RecordingLocationUsageSchema = object({
26634
26673
  * previously rendered as two identical "disks" with a nonsensical used
26635
26674
  * split — hydrate attribution across aliases is arbitrary by nature. */
26636
26675
  locationIds: array(string()).optional(),
26637
- /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
26676
+ /**
26677
+ * Filesystem root of the physical volume this row accounts — the only
26678
+ * operator-legible identity when a location has no `displayName` yet, and
26679
+ * what a "which disk is full" alert has to name. OPTIONAL for the same
26680
+ * train-skew reason as `oldestMs`: a recorder that predates the field omits
26681
+ * it, and this schema must keep validating that older provider's payload.
26682
+ */
26683
+ root: string().optional(),
26684
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
26685
+ * the footage's SHARE of the volume, not how full the volume is — the disk
26686
+ * also holds everything that is not recordings. Volume fill is
26687
+ * `(totalBytes - availableBytes) / totalBytes`. */
26638
26688
  usedBytes: number(),
26639
- /** Free bytes on the location's volume; null when capacity is unknown (remote). */
26689
+ /** Free bytes on the location's volume; null when capacity is unknown
26690
+ * (remote/unstattable — the recorder logs the statfs failure with the root). */
26640
26691
  availableBytes: number().nullable(),
26641
26692
  /** Total bytes of the location's volume; null when unknown. */
26642
26693
  totalBytes: number().nullable()
@@ -26648,7 +26699,15 @@ var RecordingStorageUsageSchema = object({
26648
26699
  nodeId: string(),
26649
26700
  totalUsedBytes: number(),
26650
26701
  devices: array(RecordingDeviceUsageSchema),
26651
- locations: array(RecordingLocationUsageSchema)
26702
+ /**
26703
+ * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
26704
+ * of the payload without it: the hub serves this method through a BAKED
26705
+ * router, so a hub whose framework train predates a change to this array
26706
+ * strips it out of an answer a newer recorder happily produced. A UI that
26707
+ * dereferences it unconditionally crashes the whole Storage page over a
26708
+ * missing disk bar.
26709
+ */
26710
+ locations: array(RecordingLocationUsageSchema).optional()
26652
26711
  });
26653
26712
  /**
26654
26713
  * The OPERATOR-ARMED half of multi-location recordings (D116).
@@ -37433,7 +37492,11 @@ Object.freeze({
37433
37492
  "network-access": "ingress",
37434
37493
  "smtp-provider": "email"
37435
37494
  });
37436
- new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
37495
+ /** Schema defaults an untouched sub-field must author exactly these. */
37496
+ var NC_AUDIO_DEFAULTS = {
37497
+ hitPercent: 60,
37498
+ samplingSeconds: 10
37499
+ };
37437
37500
  new Set(["devices", "classes"]);
37438
37501
  /** Strip a small, safe subset of Markdown down to plain text. */
37439
37502
  function markdownToText(md) {
@@ -37642,6 +37705,7 @@ function prepareNotification(caps, n) {
37642
37705
  renderedAs
37643
37706
  };
37644
37707
  }
37708
+ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
37645
37709
  /**
37646
37710
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
37647
37711
  *
@@ -37873,6 +37937,39 @@ TimelapseRuleInputSchema.extend({
37873
37937
  createdAt: number(),
37874
37938
  updatedAt: number()
37875
37939
  });
37940
+ Object.freeze(Object.fromEntries([{
37941
+ stepId: "face-embedding",
37942
+ label: "Face recognition model",
37943
+ defaultModelId: "arcface-r100",
37944
+ indexName: "the enrolled face gallery",
37945
+ options: [
37946
+ {
37947
+ id: "arcface-r100",
37948
+ label: "ArcFace (ResNet34)"
37949
+ },
37950
+ {
37951
+ id: "auraface-r100",
37952
+ label: "AuraFace R100"
37953
+ },
37954
+ {
37955
+ id: "inception-resnet-v1",
37956
+ label: "Inception ResNet V1"
37957
+ }
37958
+ ]
37959
+ }, {
37960
+ stepId: "clip-embedding",
37961
+ label: "Semantic search model",
37962
+ defaultModelId: "mobileclip-s1",
37963
+ indexName: "the object semantic-search index",
37964
+ options: [{
37965
+ id: "mobileclip-s1",
37966
+ label: "MobileCLIP S1"
37967
+ }, {
37968
+ id: "mobileclip-s2",
37969
+ label: "MobileCLIP S2"
37970
+ }]
37971
+ }].map((s) => [s.stepId, s.defaultModelId])));
37972
+ string().min(1);
37876
37973
  object({
37877
37974
  /**
37878
37975
  * Fraction of the box's own size added on EACH side before cutting.
@@ -37893,10 +37990,21 @@ object({
37893
37990
  */
37894
37991
  square: boolean()
37895
37992
  });
37896
- ({
37993
+ /**
37994
+ * The convention in force when nobody has configured one — byte-for-byte the
37995
+ * behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
37996
+ */
37997
+ var DEFAULT_DETAIL_CROP_CONVENTION = {
37897
37998
  paddingRatio: .15,
37898
37999
  square: false
37899
- }).paddingRatio;
38000
+ };
38001
+ Object.freeze({
38002
+ x: 0,
38003
+ y: 0,
38004
+ w: 1,
38005
+ h: 1
38006
+ });
38007
+ DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
37900
38008
  /**
37901
38009
  * WHICH delivered frames the decode worker retains a native copy of.
37902
38010
  *
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  //#endregion
6
- const require_dist = require("../dist-DCvHGfFW.js");
6
+ const require_dist = require("../dist-Cnf3N7Ug.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  //#region src/ha-export/topics.ts
9
9
  /**
@@ -1,4 +1,4 @@
1
- import { M as deviceExportCapability, Ot as EventCategory, S as buildAddonRouteProvider, Y as oauthIntegrationCapability, a as CameraSwitchIdSchema, c as HvacModeSchema, f as addonRoutesCapability, ft as BaseAddon, i as COCO_TO_MACRO, l as MediaPlayerRepeatSchema, s as FanDirectionSchema, t as AlarmArmModeSchema, wt as string } from "../dist-DObg5VV6.mjs";
1
+ import { M as deviceExportCapability, Ot as EventCategory, S as buildAddonRouteProvider, Y as oauthIntegrationCapability, a as CameraSwitchIdSchema, c as HvacModeSchema, f as addonRoutesCapability, ft as BaseAddon, i as COCO_TO_MACRO, l as MediaPlayerRepeatSchema, s as FanDirectionSchema, t as AlarmArmModeSchema, wt as string } from "../dist-CZfScvEk.mjs";
2
2
  import { createHmac, timingSafeEqual } from "node:crypto";
3
3
  //#region src/ha-export/topics.ts
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-homeassistant",
3
- "version": "1.2.35",
3
+ "version": "1.2.37",
4
4
  "description": "Home Assistant device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",