@camstack/addon-provider-homeassistant 1.2.634 → 1.2.636

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.
@@ -5580,7 +5580,7 @@ var ZodIssueCode = {
5580
5580
  var ZodFirstPartyTypeKind;
5581
5581
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5582
5582
  //#endregion
5583
- //#region ../types/dist/sleep-Crlmu_tO.mjs
5583
+ //#region ../types/dist/sleep-DJws6ho7.mjs
5584
5584
  /**
5585
5585
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5586
5586
  * window to float samples (D455).
@@ -9035,6 +9035,7 @@ var CAP_NAMES = Object.freeze([
9035
9035
  "image-settings",
9036
9036
  "integrations",
9037
9037
  "intercom",
9038
+ "ir-transmitter",
9038
9039
  "keychain",
9039
9040
  "keychain-admin",
9040
9041
  "lawn-mower-control",
@@ -9093,6 +9094,7 @@ var CAP_NAMES = Object.freeze([
9093
9094
  "recording-onboard",
9094
9095
  "recording-signal",
9095
9096
  "records",
9097
+ "remote",
9096
9098
  "running-state",
9097
9099
  "scene-monitor",
9098
9100
  "script-runner",
@@ -9116,6 +9118,7 @@ var CAP_NAMES = Object.freeze([
9116
9118
  "system",
9117
9119
  "tamper",
9118
9120
  "temperature-sensor",
9121
+ "template",
9119
9122
  "terminal-session",
9120
9123
  "toast",
9121
9124
  "training",
@@ -10056,6 +10059,11 @@ Object.freeze({
10056
10059
  "standby"
10057
10060
  ]
10058
10061
  },
10062
+ {
10063
+ "path": "stateSource",
10064
+ "valueType": "enum",
10065
+ "enumValues": ["reported", "assumed"]
10066
+ },
10059
10067
  {
10060
10068
  "path": "volumeLevel",
10061
10069
  "valueType": "number"
@@ -10282,6 +10290,11 @@ Object.freeze({
10282
10290
  "path": "batteryPower",
10283
10291
  "valueType": "number"
10284
10292
  },
10293
+ {
10294
+ "path": "powerSource",
10295
+ "valueType": "enum",
10296
+ "enumValues": ["mains", "battery"]
10297
+ },
10285
10298
  {
10286
10299
  "path": "desiccantLeftDays",
10287
10300
  "valueType": "number"
@@ -10326,6 +10339,18 @@ Object.freeze({
10326
10339
  {
10327
10340
  "path": "volume",
10328
10341
  "valueType": "number"
10342
+ },
10343
+ {
10344
+ "path": "lastFeedGrams",
10345
+ "valueType": "number"
10346
+ },
10347
+ {
10348
+ "path": "lastFeedHopper1",
10349
+ "valueType": "number"
10350
+ },
10351
+ {
10352
+ "path": "lastFeedHopper2",
10353
+ "valueType": "number"
10329
10354
  }
10330
10355
  ],
10331
10356
  "power-meter": [
@@ -10865,7 +10890,7 @@ object({
10865
10890
  params: record(string(), union([string(), number()])).optional()
10866
10891
  });
10867
10892
  //#endregion
10868
- //#region ../types/dist/err-msg-DIorGYeC.mjs
10893
+ //#region ../types/dist/err-msg-BCdlR2Li.mjs
10869
10894
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
10870
10895
  DeviceType["Camera"] = "camera";
10871
10896
  DeviceType["Hub"] = "hub";
@@ -11211,6 +11236,9 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
11211
11236
  /** Fallback when the notifier service name doesn't match a known
11212
11237
  * pattern. */
11213
11238
  DeviceRole["GenericNotifier"] = "generic-notifier";
11239
+ /** Emits a pulse train (infrared or RF) on request — the `ir-transmitter`
11240
+ * cap. A `DeviceType.Generic` device. */
11241
+ DeviceRole["IrTransmitter"] = "ir-transmitter";
11214
11242
  return DeviceRole;
11215
11243
  }({});
11216
11244
  /**
@@ -11224,7 +11252,7 @@ function errMsg(err) {
11224
11252
  return String(err);
11225
11253
  }
11226
11254
  //#endregion
11227
- //#region ../types/dist/composition-CZImLpOI.mjs
11255
+ //#region ../types/dist/composition-DpFv_J6D.mjs
11228
11256
  /**
11229
11257
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11230
11258
  *
@@ -16797,9 +16825,21 @@ var AlertSeveritySchema = _enum([
16797
16825
  "error",
16798
16826
  "critical"
16799
16827
  ]);
16828
+ /**
16829
+ * An action that RUNS something instead of going somewhere: the admin UI calls
16830
+ * the addon's custom action (`addons.custom`) with exactly these fields. The
16831
+ * producer owns the meaning; the UI knows nothing about the addon or the kind.
16832
+ */
16833
+ var AlertActionInvokeSchema = object({
16834
+ addonId: string().min(1),
16835
+ action: string().min(1),
16836
+ input: record(string(), unknown()).optional()
16837
+ });
16838
+ /** An action has `href` (a link) OR `invoke` (a button that runs a custom action). */
16800
16839
  var AlertActionSchema = object({
16801
16840
  label: string(),
16802
16841
  href: string().optional(),
16842
+ invoke: AlertActionInvokeSchema.optional(),
16803
16843
  /**
16804
16844
  * How `href` is followed. Absent / `app`: an admin-ui route (client-side).
16805
16845
  * `server`: a route the HUB serves (an addon HTTP route such as an OAuth
@@ -19454,12 +19494,13 @@ var CHANGED = {
19454
19494
  expr: "now"
19455
19495
  };
19456
19496
  function numeric(input) {
19497
+ const { alsoFrom, ...base } = input;
19457
19498
  return {
19458
- ...input,
19499
+ ...base,
19459
19500
  family: "numeric",
19460
19501
  deviceType: DeviceType.Sensor,
19461
19502
  memberDeviceType: DeviceType.Sensor,
19462
- memberDeviceTypes: [DeviceType.Sensor],
19503
+ memberDeviceTypes: [DeviceType.Sensor, ...alsoFrom?.deviceTypes ?? []],
19463
19504
  activeWhen: void 0,
19464
19505
  commandCaps: [],
19465
19506
  baseUnit: baseUnitOf(input.quantity),
@@ -19467,9 +19508,10 @@ function numeric(input) {
19467
19508
  accept: [{
19468
19509
  cap: input.outputCap,
19469
19510
  fieldPath: input.outputField
19470
- }]
19511
+ }, ...alsoFrom === void 0 ? [] : [alsoFrom.accept]]
19471
19512
  };
19472
19513
  }
19514
+ var CLIMATE_DEVICES = [DeviceType.Thermostat, DeviceType.Climate];
19473
19515
  function binary(input) {
19474
19516
  return {
19475
19517
  ...input,
@@ -19495,7 +19537,14 @@ var GROUP_TEMPLATES = [
19495
19537
  quantity: "temperature",
19496
19538
  defaultAggregate: "mean",
19497
19539
  empty: "null",
19498
- companions: [NOW$2]
19540
+ companions: [NOW$2],
19541
+ alsoFrom: {
19542
+ deviceTypes: CLIMATE_DEVICES,
19543
+ accept: {
19544
+ cap: "climate-control",
19545
+ fieldPath: "currentTemp"
19546
+ }
19547
+ }
19499
19548
  }),
19500
19549
  numeric({
19501
19550
  id: "humidity",
@@ -19506,7 +19555,14 @@ var GROUP_TEMPLATES = [
19506
19555
  quantity: "humidity",
19507
19556
  defaultAggregate: "mean",
19508
19557
  empty: "null",
19509
- companions: [NOW$2]
19558
+ companions: [NOW$2],
19559
+ alsoFrom: {
19560
+ deviceTypes: CLIMATE_DEVICES,
19561
+ accept: {
19562
+ cap: "climate-control",
19563
+ fieldPath: "currentHumidity"
19564
+ }
19565
+ }
19510
19566
  }),
19511
19567
  numeric({
19512
19568
  id: "pressure",
@@ -44179,6 +44235,17 @@ var LlmProfileSchema = object({
44179
44235
  * field in its editor only when its descriptor lists it in `profileFields`. */
44180
44236
  topK: number().int().positive().optional(),
44181
44237
  maxTokens: number().int().positive().optional(),
44238
+ /** How hard the model "thinks" before it answers. Omitted = the model's own
44239
+ * default. `off` matters for structured output: a thinking model can spend
44240
+ * the whole completion on reasoning and return an empty `content`. Carried
44241
+ * only by the wires that have it — a kind offers the field in its editor
44242
+ * only when its descriptor lists it in `profileFields`. */
44243
+ reasoningEffort: _enum([
44244
+ "off",
44245
+ "low",
44246
+ "medium",
44247
+ "high"
44248
+ ]).optional(),
44182
44249
  /** Prompt context window. Advisory for cloud kinds (they enforce their own). */
44183
44250
  contextLength: number().int().positive().optional(),
44184
44251
  /** Default system prompt. A caller's `system` REPLACES it (never appends —
@@ -44217,6 +44284,7 @@ var LlmProfileFieldSchema = _enum([
44217
44284
  "topP",
44218
44285
  "topK",
44219
44286
  "maxTokens",
44287
+ "reasoningEffort",
44220
44288
  "contextLength",
44221
44289
  "systemPrompt",
44222
44290
  "timeoutMs",
@@ -45467,6 +45535,43 @@ var NotificationActionSchema = object({
45467
45535
  */
45468
45536
  mode: _enum(["navigate", "background"]).optional()
45469
45537
  });
45538
+ /** A delivery parameter value: what a notifier declared it takes. */
45539
+ var DeliveryParamValueSchema = union([
45540
+ string(),
45541
+ number(),
45542
+ boolean()
45543
+ ]);
45544
+ /**
45545
+ * One extra delivery parameter a notifier KIND declares (D938). A rule that
45546
+ * addresses a target of that kind may set it; a kind that declares nothing is
45547
+ * never handed one. The admin UI derives its control from this descriptor —
45548
+ * no editor knows a service by name.
45549
+ *
45550
+ * Optional fields are `.optional()`, never `.default()` (a Zod default does not
45551
+ * run on the addon cap path).
45552
+ */
45553
+ var DeliveryParamSchema = object({
45554
+ key: string().min(1),
45555
+ label: string(),
45556
+ /** i18n key of the label, resolved by the declaring addon's namespace. */
45557
+ labelKey: string().optional(),
45558
+ type: _enum([
45559
+ "enum",
45560
+ "number",
45561
+ "boolean",
45562
+ "string"
45563
+ ]),
45564
+ /** `enum` only: the closed set of accepted values. */
45565
+ options: array(object({
45566
+ value: string(),
45567
+ label: string()
45568
+ })).optional(),
45569
+ /** `number` only. */
45570
+ min: number().optional(),
45571
+ max: number().optional(),
45572
+ /** What the notifier does when the rule sets nothing; shown as the placeholder. */
45573
+ default: DeliveryParamValueSchema.optional()
45574
+ });
45470
45575
  /**
45471
45576
  * The canonical notification. `body` is the only hard field (Apprise model).
45472
45577
  * `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
@@ -45489,7 +45594,13 @@ var NotificationSchema = object({
45489
45594
  tag: string().optional(),
45490
45595
  deviceId: number().optional(),
45491
45596
  eventId: string().optional(),
45492
- metadata: record(string(), unknown()).optional()
45597
+ metadata: record(string(), unknown()).optional(),
45598
+ /**
45599
+ * Values for the parameters the target's kind DECLARES in
45600
+ * {@link TargetKindSchema} `deliveryParams`. Already validated against the
45601
+ * declaration by the sender; a notifier reads only the keys it declared.
45602
+ */
45603
+ delivery: record(string(), DeliveryParamValueSchema).optional()
45493
45604
  });
45494
45605
  /** One declared native severity/priority level for a kind. */
45495
45606
  var TargetKindLevelSchema = object({
@@ -45595,6 +45706,11 @@ var TargetKindSchema = object({
45595
45706
  */
45596
45707
  destinationKeys: array(string()).optional(),
45597
45708
  supportsDiscovery: boolean(),
45709
+ /**
45710
+ * Extra delivery parameters a rule may set for a target of this kind (D938).
45711
+ * Absent = none; the rule editor then offers nothing.
45712
+ */
45713
+ deliveryParams: array(DeliveryParamSchema).optional(),
45598
45714
  caps: TargetKindCapsSchema
45599
45715
  });
45600
45716
  /**
@@ -57996,7 +58112,9 @@ var ManifestShapeSchema = object({
57996
58112
  icon: string().optional()
57997
58113
  }).optional(),
57998
58114
  protected: boolean().optional(),
57999
- removable: boolean().optional()
58115
+ removable: boolean().optional(),
58116
+ /** Declared Integrations-page block (mirror of `AddonDeclaration.integrationSection`). */
58117
+ integrationSection: _enum(["system", "providers"]).optional()
58000
58118
  });
58001
58119
  var AddonProcessSchema = object({
58002
58120
  pid: number().optional(),
@@ -59126,6 +59244,318 @@ onBrightnessChanged: { data: object({
59126
59244
  } } }
59127
59245
  };
59128
59246
  /**
59247
+ * The role vocabulary of a remote (D963): what a button MEANS, independent of
59248
+ * how it is wired. A layout template places buttons by role; a device binds a
59249
+ * role to an action; an exporter asks for a role by name. Roles are shared so
59250
+ * one layout fits every appliance and one voice command fits every binding.
59251
+ *
59252
+ * A role outside this list is `custom:<key>` — the operator's own button (a
59253
+ * SmartIR source, a channel preset). The key is a lowercase slug.
59254
+ */
59255
+ var REMOTE_KNOWN_ROLES = [
59256
+ "power",
59257
+ "power_on",
59258
+ "power_off",
59259
+ "volume_up",
59260
+ "volume_down",
59261
+ "mute",
59262
+ "channel_up",
59263
+ "channel_down",
59264
+ "up",
59265
+ "down",
59266
+ "left",
59267
+ "right",
59268
+ "ok",
59269
+ "back",
59270
+ "home",
59271
+ "menu",
59272
+ "info",
59273
+ "guide",
59274
+ "exit",
59275
+ "input",
59276
+ "play",
59277
+ "pause",
59278
+ "play_pause",
59279
+ "stop",
59280
+ "next",
59281
+ "previous",
59282
+ "fast_forward",
59283
+ "rewind",
59284
+ "digit_0",
59285
+ "digit_1",
59286
+ "digit_2",
59287
+ "digit_3",
59288
+ "digit_4",
59289
+ "digit_5",
59290
+ "digit_6",
59291
+ "digit_7",
59292
+ "digit_8",
59293
+ "digit_9"
59294
+ ];
59295
+ var CUSTOM_KEY_RE = /^[a-z0-9][a-z0-9_]{0,47}$/;
59296
+ var KNOWN_ROLES = new Set(REMOTE_KNOWN_ROLES);
59297
+ function isRemoteKnownRole(value) {
59298
+ return KNOWN_ROLES.has(value);
59299
+ }
59300
+ function isRemoteCustomKey(key) {
59301
+ return CUSTOM_KEY_RE.test(key);
59302
+ }
59303
+ /** The key of a `custom:<key>` role, or null for any other string. */
59304
+ function customKeyOfRole(role) {
59305
+ if (!role.startsWith("custom:")) return null;
59306
+ const key = role.slice(7);
59307
+ return isRemoteCustomKey(key) ? key : null;
59308
+ }
59309
+ function isRemoteRole(value) {
59310
+ return isRemoteKnownRole(value) || customKeyOfRole(value) !== null;
59311
+ }
59312
+ var RemoteRoleSchema = string().refine(isRemoteRole, { message: "a role is one of the known roles or custom:<key> (lowercase letters, digits, _)" });
59313
+ var RemoteBindingSchema = object({ action: AutomationCapStepSchema.extend({ deviceId: number().int().nonnegative() }) });
59314
+ var RemoteCustomButtonSchema = object({
59315
+ /** The slug after `custom:` in the role. */
59316
+ key: string().refine(isRemoteCustomKey, { message: "a lowercase slug" }),
59317
+ /** What the operator calls it, and what a voice command may name. */
59318
+ name: string().min(1).max(60)
59319
+ });
59320
+ var RemotePowerModeSchema = _enum(["toggle", "discrete"]);
59321
+ var RemoteConfigSchema = object({
59322
+ layoutTemplateId: string().min(1).nullable(),
59323
+ /**
59324
+ * The transmitter device new bindings and an import send through. A binding
59325
+ * names its own device, so one command may override it.
59326
+ */
59327
+ defaultTransmitterId: number().int().nonnegative().nullable().default(null),
59328
+ /** Keyed by role. A role with no entry falls back to the native cap. */
59329
+ bindings: record(string(), RemoteBindingSchema),
59330
+ customButtons: array(RemoteCustomButtonSchema).max(100),
59331
+ power: object({ mode: RemotePowerModeSchema })
59332
+ }).superRefine((config, ctx) => {
59333
+ const roles = Object.keys(config.bindings);
59334
+ if (roles.length > 200) ctx.addIssue({
59335
+ code: "custom",
59336
+ message: "too many bindings",
59337
+ path: ["bindings"]
59338
+ });
59339
+ for (const role of roles) if (!isRemoteRole(role)) ctx.addIssue({
59340
+ code: "custom",
59341
+ message: `"${role}" is not a role`,
59342
+ path: ["bindings", role]
59343
+ });
59344
+ const keys = /* @__PURE__ */ new Set();
59345
+ config.customButtons.forEach((button, index) => {
59346
+ if (keys.has(button.key)) ctx.addIssue({
59347
+ code: "custom",
59348
+ message: `custom button "${button.key}" is listed twice`,
59349
+ path: [
59350
+ "customButtons",
59351
+ index,
59352
+ "key"
59353
+ ]
59354
+ });
59355
+ keys.add(button.key);
59356
+ });
59357
+ for (const role of roles) {
59358
+ const key = customKeyOfRole(role);
59359
+ if (key !== null && !keys.has(key)) ctx.addIssue({
59360
+ code: "custom",
59361
+ message: `${role} is bound but has no entry in customButtons`,
59362
+ path: ["bindings", role]
59363
+ });
59364
+ }
59365
+ });
59366
+ object({
59367
+ power: object({
59368
+ state: _enum(["on", "off"]),
59369
+ at: number()
59370
+ }).nullable(),
59371
+ muted: object({
59372
+ value: boolean(),
59373
+ at: number()
59374
+ }).nullable()
59375
+ });
59376
+ var RemoteLayoutButtonSchema = object({
59377
+ id: string().min(1).max(40),
59378
+ /** 0-based grid position. */
59379
+ row: number().int().min(0).max(24),
59380
+ col: number().int().min(0).max(24),
59381
+ rowSpan: number().int().min(1).max(24),
59382
+ colSpan: number().int().min(1).max(24),
59383
+ icon: string().min(1).max(60).optional(),
59384
+ label: string().min(1).max(40).optional(),
59385
+ role: RemoteRoleSchema
59386
+ });
59387
+ object({
59388
+ columns: number().int().min(1).max(24),
59389
+ rows: number().int().min(1).max(24),
59390
+ buttons: array(RemoteLayoutButtonSchema).max(200)
59391
+ }).superRefine((grid, ctx) => {
59392
+ const ids = /* @__PURE__ */ new Set();
59393
+ const taken = /* @__PURE__ */ new Map();
59394
+ grid.buttons.forEach((button, index) => {
59395
+ if (ids.has(button.id)) ctx.addIssue({
59396
+ code: "custom",
59397
+ message: `button id "${button.id}" is used twice`,
59398
+ path: [
59399
+ "buttons",
59400
+ index,
59401
+ "id"
59402
+ ]
59403
+ });
59404
+ ids.add(button.id);
59405
+ if (button.row + button.rowSpan > grid.rows || button.col + button.colSpan > grid.columns) {
59406
+ ctx.addIssue({
59407
+ code: "custom",
59408
+ message: `button "${button.id}" leaves the grid`,
59409
+ path: ["buttons", index]
59410
+ });
59411
+ return;
59412
+ }
59413
+ for (let r = button.row; r < button.row + button.rowSpan; r += 1) for (let c = button.col; c < button.col + button.colSpan; c += 1) {
59414
+ const cell = `${r}:${c}`;
59415
+ const other = taken.get(cell);
59416
+ if (other !== void 0) {
59417
+ ctx.addIssue({
59418
+ code: "custom",
59419
+ message: `buttons "${other}" and "${button.id}" overlap`,
59420
+ path: ["buttons", index]
59421
+ });
59422
+ return;
59423
+ }
59424
+ taken.set(cell, button.id);
59425
+ }
59426
+ });
59427
+ });
59428
+ var RemoteBoundCommandSchema = object({
59429
+ role: RemoteRoleSchema,
59430
+ /** The operator's name for a custom button; absent for a known role. */
59431
+ label: string().optional(),
59432
+ custom: boolean()
59433
+ });
59434
+ var RemoteCommandListSchema = object({
59435
+ layoutTemplateId: string().nullable(),
59436
+ power: object({ mode: RemotePowerModeSchema }),
59437
+ /** Only the roles that are BOUND — the ones a press can reach. */
59438
+ commands: array(RemoteBoundCommandSchema)
59439
+ });
59440
+ var RemoteRefusalReasonSchema = _enum([
59441
+ "no-remote",
59442
+ "unbound-role",
59443
+ "action-failed"
59444
+ ]);
59445
+ var RemoteSendResultSchema = discriminatedUnion("status", [
59446
+ object({
59447
+ status: literal("sent"),
59448
+ /** How many times the action ran. */
59449
+ sends: number().int().min(1)
59450
+ }),
59451
+ object({
59452
+ status: literal("skipped"),
59453
+ reason: literal("already-in-state")
59454
+ }),
59455
+ object({
59456
+ status: literal("refused"),
59457
+ reason: RemoteRefusalReasonSchema,
59458
+ detail: string().optional()
59459
+ })
59460
+ ]);
59461
+ var RemoteMediaCommandSchema = _enum([
59462
+ "play",
59463
+ "pause",
59464
+ "stop",
59465
+ "next",
59466
+ "previous",
59467
+ "setMute",
59468
+ "selectSource"
59469
+ ]);
59470
+ /** A send result, or `not-routed`: the role is not bound, so the native cap answers. */
59471
+ var RemoteMediaCommandResultSchema = discriminatedUnion("status", [...RemoteSendResultSchema.options, object({ status: literal("not-routed") })]);
59472
+ var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status: literal("saved") }), object({
59473
+ status: literal("refused"),
59474
+ reason: _enum(["unknown-template", "not-a-media-player"]),
59475
+ detail: string()
59476
+ })]);
59477
+ var deviceInput = object({ deviceId: number().int().nonnegative() });
59478
+ DeviceType.MediaPlayer;
59479
+ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
59480
+ kind: "mutation",
59481
+ auth: "admin"
59482
+ }), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
59483
+ role: RemoteRoleSchema,
59484
+ /** Sends in a row (volume steps). */
59485
+ repeat: number().int().min(1).max(50).default(1)
59486
+ }), RemoteSendResultSchema, {
59487
+ kind: "mutation",
59488
+ auth: "protected"
59489
+ }), method(deviceInput.extend({
59490
+ command: RemoteMediaCommandSchema,
59491
+ muted: boolean().optional(),
59492
+ source: string().optional(),
59493
+ repeat: number().int().min(1).max(50).default(1)
59494
+ }), RemoteMediaCommandResultSchema, {
59495
+ kind: "mutation",
59496
+ auth: "protected"
59497
+ });
59498
+ var TemplateKindSchema = _enum(["remote"]);
59499
+ /**
59500
+ * template — the generic store of reusable, named operator data (D963). A
59501
+ * record is `{ id, kind, name, payload }`; the kinds (today only `remote`, the
59502
+ * button grid of a remote) and the schema each payload must satisfy are
59503
+ * declared by the system in `template-kinds.ts`. Nothing here is specific to a
59504
+ * kind: the engine validates a payload against its kind's schema and, on a
59505
+ * delete, asks the kind's owner whether anything still points at the record.
59506
+ *
59507
+ * Every refusal is a typed result — a UI says "unknown kind" or names the
59508
+ * devices that still use a template, without parsing text.
59509
+ */
59510
+ var TemplateRecordSchema = object({
59511
+ id: string().min(1),
59512
+ kind: TemplateKindSchema,
59513
+ name: string().min(1).max(120),
59514
+ /** Shaped by the kind; `checkTemplatePayload(kind, payload)` reads it. */
59515
+ payload: unknown(),
59516
+ createdAt: number(),
59517
+ updatedAt: number()
59518
+ });
59519
+ var TemplateWriteResultSchema = discriminatedUnion("status", [object({
59520
+ status: literal("saved"),
59521
+ template: TemplateRecordSchema
59522
+ }), object({
59523
+ status: literal("refused"),
59524
+ reason: _enum(["invalid-payload", "not-found"]),
59525
+ detail: string()
59526
+ })]);
59527
+ /** A device still pointing at a template. */
59528
+ var TemplateUserSchema = object({
59529
+ deviceId: number().int().nonnegative(),
59530
+ name: string()
59531
+ });
59532
+ var TemplateDeleteResultSchema = discriminatedUnion("status", [
59533
+ object({ status: literal("deleted") }),
59534
+ object({ status: literal("not-found") }),
59535
+ object({
59536
+ status: literal("in-use"),
59537
+ devices: array(TemplateUserSchema).min(1)
59538
+ })
59539
+ ]);
59540
+ method(object({ kind: TemplateKindSchema.optional() }), array(TemplateRecordSchema), { auth: "protected" }), method(object({ id: string().min(1) }), TemplateRecordSchema.nullable(), { auth: "protected" }), method(object({
59541
+ kind: TemplateKindSchema,
59542
+ name: string().min(1).max(120),
59543
+ payload: unknown()
59544
+ }), TemplateWriteResultSchema, {
59545
+ kind: "mutation",
59546
+ auth: "admin"
59547
+ }), method(object({
59548
+ id: string().min(1),
59549
+ name: string().min(1).max(120).optional(),
59550
+ payload: unknown().optional()
59551
+ }), TemplateWriteResultSchema, {
59552
+ kind: "mutation",
59553
+ auth: "admin"
59554
+ }), method(object({ id: string().min(1) }), TemplateDeleteResultSchema, {
59555
+ kind: "mutation",
59556
+ auth: "admin"
59557
+ });
59558
+ /**
59129
59559
  * button — device-scoped capability for HA `button.*` / `input_button.*`
59130
59560
  * fire-only actuators. A button entity has no readable state — pressing it
59131
59561
  * triggers an action on the HA side. There is no `status` / `runtimeState`:
@@ -59147,6 +59577,56 @@ var buttonCapability = {
59147
59577
  }) }
59148
59578
  };
59149
59579
  /**
59580
+ * A pulse train in signed microseconds: mark (+) first, then space (-), strictly
59581
+ * alternating, no zeros, 2..1024 entries.
59582
+ */
59583
+ var IrTimingsSchema = array(number().int()).min(2).max(1024).superRefine((timings, ctx) => {
59584
+ timings.forEach((value, index) => {
59585
+ const expectMark = index % 2 === 0;
59586
+ if (value === 0 || value > 0 !== expectMark) ctx.addIssue({
59587
+ code: "custom",
59588
+ message: `timing ${index} must be a non-zero ${expectMark ? "mark (positive)" : "space (negative)"}`,
59589
+ path: [index]
59590
+ });
59591
+ });
59592
+ });
59593
+ /** Per-command transmit options. Every key is optional; a transmitter applies what it can. */
59594
+ var TransmitSettingsSchema = object({
59595
+ carrierHz: number().int().positive().optional(),
59596
+ dutyCyclePercent: number().int().min(1).max(100).optional(),
59597
+ repeat: number().int().min(0).max(20).optional(),
59598
+ repeatDelayMs: number().int().min(0).optional()
59599
+ });
59600
+ /** The setting keys a transmitter may declare as settable (`getInfo.settable`). */
59601
+ var TransmitSettingKeySchema = _enum([
59602
+ "carrierHz",
59603
+ "dutyCyclePercent",
59604
+ "repeat",
59605
+ "repeatDelayMs"
59606
+ ]);
59607
+ var IrMediumSchema = _enum(["ir", "rf"]);
59608
+ var IrSendResultSchema = object({
59609
+ ok: literal(true),
59610
+ /** Settings the transmitter could not apply; the train was still sent. */
59611
+ ignoredSettings: array(string())
59612
+ });
59613
+ var IrTransmitterInfoSchema = object({
59614
+ media: array(IrMediumSchema),
59615
+ settable: array(TransmitSettingKeySchema),
59616
+ maxTimings: number().int().positive()
59617
+ });
59618
+ DeviceType.Generic, method(object({
59619
+ deviceId: number().int().nonnegative(),
59620
+ timings: IrTimingsSchema,
59621
+ settings: TransmitSettingsSchema.optional()
59622
+ }), IrSendResultSchema, {
59623
+ kind: "mutation",
59624
+ auth: "protected"
59625
+ }), method(object({ deviceId: number().int().nonnegative() }), IrTransmitterInfoSchema, {
59626
+ kind: "query",
59627
+ auth: "protected"
59628
+ });
59629
+ /**
59150
59630
  * `calendar-source` — collection cap exposing per-provider calendars and
59151
59631
  * their events. Every addon that contributes calendars (Home Assistant,
59152
59632
  * a future Google Calendar addon, …) registers a provider here. The hub
@@ -63277,9 +63757,35 @@ var MediaInfoSchema = object({
63277
63757
  /** Optional cover-art / thumbnail URL. */
63278
63758
  imageUrl: string().optional()
63279
63759
  });
63760
+ /**
63761
+ * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
63762
+ * the device said so. `assumed`: the driver has no feedback (infrared) and
63763
+ * tracks what it last SENT; it moves only after a send was accepted, and a
63764
+ * human at the real remote makes it wrong. A UI shows an assumed value as a
63765
+ * guess, never as a reading.
63766
+ */
63767
+ var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
63768
+ /** The fields of a media-player status a driver can only guess. */
63769
+ var MediaPlayerAssumedFieldSchema = _enum([
63770
+ "state",
63771
+ "volumeLevel",
63772
+ "isMuted",
63773
+ "source"
63774
+ ]);
63280
63775
  var MediaPlayerStatusSchema = object({
63281
63776
  /** Playback lifecycle state. */
63282
63777
  state: MediaPlayerStateSchema,
63778
+ /**
63779
+ * Whether the state fields are readings or the driver's own bookkeeping.
63780
+ * A slice written before this field existed parses as `reported`.
63781
+ */
63782
+ stateSource: MediaPlayerStateSourceSchema.default("reported"),
63783
+ /**
63784
+ * Which fields are the driver's own guess. `stateSource` is `assumed` when
63785
+ * this is not empty; a field not listed here is a reading even then (power
63786
+ * from a running-state source, mute guessed from the last send).
63787
+ */
63788
+ assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
63283
63789
  /** Volume as 0..100 inclusive. Null when the device has no volume
63284
63790
  * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
63285
63791
  volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -65207,9 +65713,14 @@ var PetFeederStatusSchema = object({
65207
65713
  * (`device_class: problem`, on = low). True when the tank reports empty,
65208
65714
  * or, on a dual-hopper model, when EITHER hopper is empty. */
65209
65715
  lowFood: boolean(),
65210
- /** Battery charge 0..100 (%). Null on mains-powered models or when the
65211
- * device has no battery reading. */
65716
+ /** Battery charge 0..100 (%). On a feeder running on `mains` this is the
65717
+ * BACKUP battery's charge, not the power source. Null when the device has
65718
+ * no battery reading. */
65212
65719
  batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
65720
+ /** What the feeder is powered from right now: `mains` (plugged in, the
65721
+ * battery is only a backup) or `battery`. Null when the device does not
65722
+ * report it. */
65723
+ powerSource: _enum(["mains", "battery"]).nullable(),
65213
65724
  /**
65214
65725
  * Desiccant life remaining, stored in seconds (duration base, D944).
65215
65726
  * Providers convert from the days the feeder reports. Null when the
@@ -65237,6 +65748,14 @@ var PetFeederStatusSchema = object({
65237
65748
  feedSound: boolean(),
65238
65749
  /** Speaker / prompt volume level (device-scaled integer). */
65239
65750
  volume: number().meta(readingMeta("none")),
65751
+ /** Portion (grams) of the last manual feed sent from a single-hopper
65752
+ * stepper — the default the next manual feed starts from. Persisted per
65753
+ * device by the provider; null until a manual feed has been sent. */
65754
+ lastFeedGrams: gramsPortion.nullable(),
65755
+ /** Hopper-1 portion of the last manual feed (dual-hopper); null until sent. */
65756
+ lastFeedHopper1: gramsPortion.nullable(),
65757
+ /** Hopper-2 portion of the last manual feed (dual-hopper); null until sent. */
65758
+ lastFeedHopper2: gramsPortion.nullable(),
65240
65759
  /** Ms epoch when the slice was last refreshed from the cloud. */
65241
65760
  lastFetchedAt: number()
65242
65761
  });
@@ -71282,6 +71801,14 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
71282
71801
  kind: "mutation",
71283
71802
  auth: "admin"
71284
71803
  });
71804
+ discriminatedUnion("kind", [object({
71805
+ kind: literal("raw"),
71806
+ timings: array(number().int()),
71807
+ settings: TransmitSettingsSchema.optional()
71808
+ }), object({
71809
+ kind: literal("pronto"),
71810
+ code: string()
71811
+ })]);
71285
71812
  function resolveSince(running, previous, transitionAtMs, bootstrapSinceMs) {
71286
71813
  if (running === null) return null;
71287
71814
  const prevRunning = previous?.running ?? null;
@@ -71719,7 +72246,7 @@ function tryConvertDelta(value, from, to) {
71719
72246
  return shifted - origin;
71720
72247
  }
71721
72248
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
71722
- DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
72249
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
71723
72250
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
71724
72251
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
71725
72252
  new Set(CAP_NAMES);
@@ -76872,6 +77399,20 @@ Object.freeze({
76872
77399
  access: "create",
76873
77400
  role: "viewer"
76874
77401
  },
77402
+ "irTransmitter.getInfo": {
77403
+ capName: "ir-transmitter",
77404
+ capScope: "device",
77405
+ addonId: null,
77406
+ access: "view",
77407
+ role: "viewer"
77408
+ },
77409
+ "irTransmitter.send": {
77410
+ capName: "ir-transmitter",
77411
+ capScope: "device",
77412
+ addonId: null,
77413
+ access: "create",
77414
+ role: "viewer"
77415
+ },
76875
77416
  "keychain.delete": {
76876
77417
  capName: "keychain",
76877
77418
  capScope: "system",
@@ -80995,6 +81536,41 @@ Object.freeze({
80995
81536
  access: "create",
80996
81537
  role: "admin"
80997
81538
  },
81539
+ "remote.getConfig": {
81540
+ capName: "remote",
81541
+ capScope: "system",
81542
+ addonId: null,
81543
+ access: "view",
81544
+ role: "admin"
81545
+ },
81546
+ "remote.listCommands": {
81547
+ capName: "remote",
81548
+ capScope: "system",
81549
+ addonId: null,
81550
+ access: "view",
81551
+ role: "admin"
81552
+ },
81553
+ "remote.sendCommand": {
81554
+ capName: "remote",
81555
+ capScope: "system",
81556
+ addonId: null,
81557
+ access: "create",
81558
+ role: "admin"
81559
+ },
81560
+ "remote.sendMediaCommand": {
81561
+ capName: "remote",
81562
+ capScope: "system",
81563
+ addonId: null,
81564
+ access: "create",
81565
+ role: "admin"
81566
+ },
81567
+ "remote.setConfig": {
81568
+ capName: "remote",
81569
+ capScope: "system",
81570
+ addonId: null,
81571
+ access: "create",
81572
+ role: "admin"
81573
+ },
80998
81574
  "runningState.getStatus": {
80999
81575
  capName: "running-state",
81000
81576
  capScope: "device",
@@ -82185,6 +82761,41 @@ Object.freeze({
82185
82761
  access: "view",
82186
82762
  role: "viewer"
82187
82763
  },
82764
+ "template.create": {
82765
+ capName: "template",
82766
+ capScope: "system",
82767
+ addonId: null,
82768
+ access: "create",
82769
+ role: "admin"
82770
+ },
82771
+ "template.delete": {
82772
+ capName: "template",
82773
+ capScope: "system",
82774
+ addonId: null,
82775
+ access: "delete",
82776
+ role: "admin"
82777
+ },
82778
+ "template.get": {
82779
+ capName: "template",
82780
+ capScope: "system",
82781
+ addonId: null,
82782
+ access: "view",
82783
+ role: "admin"
82784
+ },
82785
+ "template.list": {
82786
+ capName: "template",
82787
+ capScope: "system",
82788
+ addonId: null,
82789
+ access: "view",
82790
+ role: "admin"
82791
+ },
82792
+ "template.update": {
82793
+ capName: "template",
82794
+ capScope: "system",
82795
+ addonId: null,
82796
+ access: "create",
82797
+ role: "admin"
82798
+ },
82188
82799
  "terminalSession.adoptLegacyMonitor": {
82189
82800
  capName: "terminal-session",
82190
82801
  capScope: "system",
@@ -84495,6 +85106,11 @@ var ACTUATOR_CAP_VOCABULARY = {
84495
85106
  icon: "circle-dot"
84496
85107
  }]
84497
85108
  },
85109
+ "ir-transmitter": {
85110
+ scope: "device",
85111
+ noun: t("IR / RF transmitter", "Trasmettitore IR / RF"),
85112
+ notOperatorFacing: { send: "a raw pulse train is not something an operator composes in an automation; the remote that owns the command table sends it" }
85113
+ },
84498
85114
  control: {
84499
85115
  scope: "device",
84500
85116
  noun: t("Control", "Controllo"),
@@ -87011,6 +87627,7 @@ var SYSTEM_CAP_VOCABULARY = {
87011
87627
  "recording-archive": system(STORAGE),
87012
87628
  "recording-export": system("recording exports — requested from the timeline, not an automation step"),
87013
87629
  records: system(INTERNAL),
87630
+ remote: system("the per-device remote setup — authored in the Customize remote editor, sent through the remote UI"),
87014
87631
  "server-management": system(CLUSTER),
87015
87632
  "settings-store": system(INTERNAL),
87016
87633
  "smtp-provider": system(INTERNAL),
@@ -87023,6 +87640,7 @@ var SYSTEM_CAP_VOCABULARY = {
87023
87640
  "storage-provider": system(STORAGE),
87024
87641
  "stream-broker": system(PIPELINE),
87025
87642
  system: system(CLUSTER),
87643
+ template: system("operator-authored templates — edited in their own editor, never actuated"),
87026
87644
  "terminal-session": system(CLUSTER),
87027
87645
  toast: system(UI_PLUMBING),
87028
87646
  training: system(ML),
@@ -88225,6 +88843,16 @@ Object.freeze({
88225
88843
  form: "single",
88226
88844
  optional: false
88227
88845
  }],
88846
+ "irTransmitter.getInfo": [{
88847
+ name: "deviceId",
88848
+ form: "single",
88849
+ optional: false
88850
+ }],
88851
+ "irTransmitter.send": [{
88852
+ name: "deviceId",
88853
+ form: "single",
88854
+ optional: false
88855
+ }],
88228
88856
  "keychain.deleteDeviceScope": [{
88229
88857
  name: "deviceId",
88230
88858
  form: "single",
@@ -89450,6 +90078,31 @@ Object.freeze({
89450
90078
  form: "single",
89451
90079
  optional: true
89452
90080
  }],
90081
+ "remote.getConfig": [{
90082
+ name: "deviceId",
90083
+ form: "single",
90084
+ optional: false
90085
+ }],
90086
+ "remote.listCommands": [{
90087
+ name: "deviceId",
90088
+ form: "single",
90089
+ optional: false
90090
+ }],
90091
+ "remote.sendCommand": [{
90092
+ name: "deviceId",
90093
+ form: "single",
90094
+ optional: false
90095
+ }],
90096
+ "remote.sendMediaCommand": [{
90097
+ name: "deviceId",
90098
+ form: "single",
90099
+ optional: false
90100
+ }],
90101
+ "remote.setConfig": [{
90102
+ name: "deviceId",
90103
+ form: "single",
90104
+ optional: false
90105
+ }],
89453
90106
  "runningState.getStatus": [{
89454
90107
  name: "deviceId",
89455
90108
  form: "single",
@@ -91607,6 +92260,14 @@ function bestLocationMatch(externalName, existing, threshold = .8) {
91607
92260
  String.raw`(?<=^|["'(\s>,\[{])`;
91608
92261
  var MB = 1024 * 1024;
91609
92262
  1024 * MB, 3072 * MB;
92263
+ object({
92264
+ manufacturer: string().optional(),
92265
+ supportedModels: array(string()).optional(),
92266
+ supportedController: string().optional(),
92267
+ commandsEncoding: string(),
92268
+ delay: number().nonnegative().optional(),
92269
+ commands: record(string(), unknown())
92270
+ });
91610
92271
  //#endregion
91611
92272
  Object.defineProperty(exports, "AlarmArmModeSchema", {
91612
92273
  enumerable: true,