@camstack/addon-training 0.1.102 → 0.1.104

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 (23) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/{MotionZonesSettings-HAJ6awj4.mjs → MotionZonesSettings-Bm3-aVd_.mjs} +2 -2
  3. package/dist/{PrivacyMaskSettings-BF0NUmVm.mjs → PrivacyMaskSettings-CHKqJ1Jl.mjs} +2 -2
  4. package/dist/{SceneMonitorEditor-CeEWTp0p.mjs → SceneMonitorEditor-BLeDd1kR.mjs} +2 -2
  5. package/dist/_stub.js +1726 -1662
  6. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-p2vBd39W.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-DsiAbTAk.mjs} +3 -3
  7. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-rtY7yvpT.mjs +26 -0
  8. package/dist/addon-training.css +1 -1
  9. package/dist/{dist-u3tq3l-n.mjs → dist-CXZDrfkr.mjs} +484 -10
  10. package/dist/{dist-CNkCexYe.js → dist-DkRYepCT.js} +484 -10
  11. package/dist/{hostInit-CvBrePIu.mjs → hostInit-CkFf4SAO.mjs} +2 -2
  12. package/dist/index.js +1 -1
  13. package/dist/orchestrator/training.addon.js +1 -1
  14. package/dist/orchestrator/training.addon.mjs +1 -1
  15. package/dist/{player-overlays-NVql0bBe.mjs → player-overlays-DxLTXMBd.mjs} +1 -1
  16. package/dist/providers/modal/training-modal.addon.js +1 -1
  17. package/dist/providers/modal/training-modal.addon.mjs +1 -1
  18. package/dist/remoteEntry.js +1 -1
  19. package/dist/{responsive-Cw10UV1G.mjs → responsive-1P4H2DQA.mjs} +1 -1
  20. package/dist/{scene-monitor-copy-BiaQA_PZ.mjs → scene-monitor-copy-DmazWKcQ.mjs} +1 -1
  21. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-B2ShwDvL.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-BBdigjaL.mjs} +1 -1
  22. package/package.json +1 -1
  23. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CLeWJI6-.mjs +0 -26
@@ -5580,7 +5580,7 @@ var ZodIssueCode = {
5580
5580
  var ZodFirstPartyTypeKind;
5581
5581
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5582
5582
  //#endregion
5583
- //#region ../types/dist/sleep-BAvUCi_2.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).
@@ -9021,6 +9021,7 @@ var CAP_NAMES = Object.freeze([
9021
9021
  "recording-onboard",
9022
9022
  "recording-signal",
9023
9023
  "records",
9024
+ "remote",
9024
9025
  "running-state",
9025
9026
  "scene-monitor",
9026
9027
  "script-runner",
@@ -9044,6 +9045,7 @@ var CAP_NAMES = Object.freeze([
9044
9045
  "system",
9045
9046
  "tamper",
9046
9047
  "temperature-sensor",
9048
+ "template",
9047
9049
  "terminal-session",
9048
9050
  "toast",
9049
9051
  "training",
@@ -9984,6 +9986,11 @@ Object.freeze({
9984
9986
  "standby"
9985
9987
  ]
9986
9988
  },
9989
+ {
9990
+ "path": "stateSource",
9991
+ "valueType": "enum",
9992
+ "enumValues": ["reported", "assumed"]
9993
+ },
9987
9994
  {
9988
9995
  "path": "volumeLevel",
9989
9996
  "valueType": "number"
@@ -10259,6 +10266,18 @@ Object.freeze({
10259
10266
  {
10260
10267
  "path": "volume",
10261
10268
  "valueType": "number"
10269
+ },
10270
+ {
10271
+ "path": "lastFeedGrams",
10272
+ "valueType": "number"
10273
+ },
10274
+ {
10275
+ "path": "lastFeedHopper1",
10276
+ "valueType": "number"
10277
+ },
10278
+ {
10279
+ "path": "lastFeedHopper2",
10280
+ "valueType": "number"
10262
10281
  }
10263
10282
  ],
10264
10283
  "power-meter": [
@@ -16595,9 +16614,21 @@ var AlertSeveritySchema = _enum([
16595
16614
  "error",
16596
16615
  "critical"
16597
16616
  ]);
16617
+ /**
16618
+ * An action that RUNS something instead of going somewhere: the admin UI calls
16619
+ * the addon's custom action (`addons.custom`) with exactly these fields. The
16620
+ * producer owns the meaning; the UI knows nothing about the addon or the kind.
16621
+ */
16622
+ var AlertActionInvokeSchema = object({
16623
+ addonId: string().min(1),
16624
+ action: string().min(1),
16625
+ input: record(string(), unknown()).optional()
16626
+ });
16627
+ /** An action has `href` (a link) OR `invoke` (a button that runs a custom action). */
16598
16628
  var AlertActionSchema = object({
16599
16629
  label: string(),
16600
16630
  href: string().optional(),
16631
+ invoke: AlertActionInvokeSchema.optional(),
16601
16632
  /**
16602
16633
  * How `href` is followed. Absent / `app`: an admin-ui route (client-side).
16603
16634
  * `server`: a route the HUB serves (an addon HTTP route such as an OAuth
@@ -57748,6 +57779,318 @@ DeviceType.Light, method(object({
57748
57779
  level: number().min(0).max(100),
57749
57780
  lastChangedAt: number()
57750
57781
  });
57782
+ /**
57783
+ * The role vocabulary of a remote (D963): what a button MEANS, independent of
57784
+ * how it is wired. A layout template places buttons by role; a device binds a
57785
+ * role to an action; an exporter asks for a role by name. Roles are shared so
57786
+ * one layout fits every appliance and one voice command fits every binding.
57787
+ *
57788
+ * A role outside this list is `custom:<key>` — the operator's own button (a
57789
+ * SmartIR source, a channel preset). The key is a lowercase slug.
57790
+ */
57791
+ var REMOTE_KNOWN_ROLES = [
57792
+ "power",
57793
+ "power_on",
57794
+ "power_off",
57795
+ "volume_up",
57796
+ "volume_down",
57797
+ "mute",
57798
+ "channel_up",
57799
+ "channel_down",
57800
+ "up",
57801
+ "down",
57802
+ "left",
57803
+ "right",
57804
+ "ok",
57805
+ "back",
57806
+ "home",
57807
+ "menu",
57808
+ "info",
57809
+ "guide",
57810
+ "exit",
57811
+ "input",
57812
+ "play",
57813
+ "pause",
57814
+ "play_pause",
57815
+ "stop",
57816
+ "next",
57817
+ "previous",
57818
+ "fast_forward",
57819
+ "rewind",
57820
+ "digit_0",
57821
+ "digit_1",
57822
+ "digit_2",
57823
+ "digit_3",
57824
+ "digit_4",
57825
+ "digit_5",
57826
+ "digit_6",
57827
+ "digit_7",
57828
+ "digit_8",
57829
+ "digit_9"
57830
+ ];
57831
+ var CUSTOM_KEY_RE = /^[a-z0-9][a-z0-9_]{0,47}$/;
57832
+ var KNOWN_ROLES = new Set(REMOTE_KNOWN_ROLES);
57833
+ function isRemoteKnownRole(value) {
57834
+ return KNOWN_ROLES.has(value);
57835
+ }
57836
+ function isRemoteCustomKey(key) {
57837
+ return CUSTOM_KEY_RE.test(key);
57838
+ }
57839
+ /** The key of a `custom:<key>` role, or null for any other string. */
57840
+ function customKeyOfRole(role) {
57841
+ if (!role.startsWith("custom:")) return null;
57842
+ const key = role.slice(7);
57843
+ return isRemoteCustomKey(key) ? key : null;
57844
+ }
57845
+ function isRemoteRole(value) {
57846
+ return isRemoteKnownRole(value) || customKeyOfRole(value) !== null;
57847
+ }
57848
+ var RemoteRoleSchema = string().refine(isRemoteRole, { message: "a role is one of the known roles or custom:<key> (lowercase letters, digits, _)" });
57849
+ var RemoteBindingSchema = object({ action: AutomationCapStepSchema.extend({ deviceId: number().int().nonnegative() }) });
57850
+ var RemoteCustomButtonSchema = object({
57851
+ /** The slug after `custom:` in the role. */
57852
+ key: string().refine(isRemoteCustomKey, { message: "a lowercase slug" }),
57853
+ /** What the operator calls it, and what a voice command may name. */
57854
+ name: string().min(1).max(60)
57855
+ });
57856
+ var RemotePowerModeSchema = _enum(["toggle", "discrete"]);
57857
+ var RemoteConfigSchema = object({
57858
+ layoutTemplateId: string().min(1).nullable(),
57859
+ /**
57860
+ * The transmitter device new bindings and an import send through. A binding
57861
+ * names its own device, so one command may override it.
57862
+ */
57863
+ defaultTransmitterId: number().int().nonnegative().nullable().default(null),
57864
+ /** Keyed by role. A role with no entry falls back to the native cap. */
57865
+ bindings: record(string(), RemoteBindingSchema),
57866
+ customButtons: array(RemoteCustomButtonSchema).max(100),
57867
+ power: object({ mode: RemotePowerModeSchema })
57868
+ }).superRefine((config, ctx) => {
57869
+ const roles = Object.keys(config.bindings);
57870
+ if (roles.length > 200) ctx.addIssue({
57871
+ code: "custom",
57872
+ message: "too many bindings",
57873
+ path: ["bindings"]
57874
+ });
57875
+ for (const role of roles) if (!isRemoteRole(role)) ctx.addIssue({
57876
+ code: "custom",
57877
+ message: `"${role}" is not a role`,
57878
+ path: ["bindings", role]
57879
+ });
57880
+ const keys = /* @__PURE__ */ new Set();
57881
+ config.customButtons.forEach((button, index) => {
57882
+ if (keys.has(button.key)) ctx.addIssue({
57883
+ code: "custom",
57884
+ message: `custom button "${button.key}" is listed twice`,
57885
+ path: [
57886
+ "customButtons",
57887
+ index,
57888
+ "key"
57889
+ ]
57890
+ });
57891
+ keys.add(button.key);
57892
+ });
57893
+ for (const role of roles) {
57894
+ const key = customKeyOfRole(role);
57895
+ if (key !== null && !keys.has(key)) ctx.addIssue({
57896
+ code: "custom",
57897
+ message: `${role} is bound but has no entry in customButtons`,
57898
+ path: ["bindings", role]
57899
+ });
57900
+ }
57901
+ });
57902
+ object({
57903
+ power: object({
57904
+ state: _enum(["on", "off"]),
57905
+ at: number()
57906
+ }).nullable(),
57907
+ muted: object({
57908
+ value: boolean(),
57909
+ at: number()
57910
+ }).nullable()
57911
+ });
57912
+ var RemoteLayoutButtonSchema = object({
57913
+ id: string().min(1).max(40),
57914
+ /** 0-based grid position. */
57915
+ row: number().int().min(0).max(24),
57916
+ col: number().int().min(0).max(24),
57917
+ rowSpan: number().int().min(1).max(24),
57918
+ colSpan: number().int().min(1).max(24),
57919
+ icon: string().min(1).max(60).optional(),
57920
+ label: string().min(1).max(40).optional(),
57921
+ role: RemoteRoleSchema
57922
+ });
57923
+ object({
57924
+ columns: number().int().min(1).max(24),
57925
+ rows: number().int().min(1).max(24),
57926
+ buttons: array(RemoteLayoutButtonSchema).max(200)
57927
+ }).superRefine((grid, ctx) => {
57928
+ const ids = /* @__PURE__ */ new Set();
57929
+ const taken = /* @__PURE__ */ new Map();
57930
+ grid.buttons.forEach((button, index) => {
57931
+ if (ids.has(button.id)) ctx.addIssue({
57932
+ code: "custom",
57933
+ message: `button id "${button.id}" is used twice`,
57934
+ path: [
57935
+ "buttons",
57936
+ index,
57937
+ "id"
57938
+ ]
57939
+ });
57940
+ ids.add(button.id);
57941
+ if (button.row + button.rowSpan > grid.rows || button.col + button.colSpan > grid.columns) {
57942
+ ctx.addIssue({
57943
+ code: "custom",
57944
+ message: `button "${button.id}" leaves the grid`,
57945
+ path: ["buttons", index]
57946
+ });
57947
+ return;
57948
+ }
57949
+ for (let r = button.row; r < button.row + button.rowSpan; r += 1) for (let c = button.col; c < button.col + button.colSpan; c += 1) {
57950
+ const cell = `${r}:${c}`;
57951
+ const other = taken.get(cell);
57952
+ if (other !== void 0) {
57953
+ ctx.addIssue({
57954
+ code: "custom",
57955
+ message: `buttons "${other}" and "${button.id}" overlap`,
57956
+ path: ["buttons", index]
57957
+ });
57958
+ return;
57959
+ }
57960
+ taken.set(cell, button.id);
57961
+ }
57962
+ });
57963
+ });
57964
+ var RemoteBoundCommandSchema = object({
57965
+ role: RemoteRoleSchema,
57966
+ /** The operator's name for a custom button; absent for a known role. */
57967
+ label: string().optional(),
57968
+ custom: boolean()
57969
+ });
57970
+ var RemoteCommandListSchema = object({
57971
+ layoutTemplateId: string().nullable(),
57972
+ power: object({ mode: RemotePowerModeSchema }),
57973
+ /** Only the roles that are BOUND — the ones a press can reach. */
57974
+ commands: array(RemoteBoundCommandSchema)
57975
+ });
57976
+ var RemoteRefusalReasonSchema = _enum([
57977
+ "no-remote",
57978
+ "unbound-role",
57979
+ "action-failed"
57980
+ ]);
57981
+ var RemoteSendResultSchema = discriminatedUnion("status", [
57982
+ object({
57983
+ status: literal("sent"),
57984
+ /** How many times the action ran. */
57985
+ sends: number().int().min(1)
57986
+ }),
57987
+ object({
57988
+ status: literal("skipped"),
57989
+ reason: literal("already-in-state")
57990
+ }),
57991
+ object({
57992
+ status: literal("refused"),
57993
+ reason: RemoteRefusalReasonSchema,
57994
+ detail: string().optional()
57995
+ })
57996
+ ]);
57997
+ var RemoteMediaCommandSchema = _enum([
57998
+ "play",
57999
+ "pause",
58000
+ "stop",
58001
+ "next",
58002
+ "previous",
58003
+ "setMute",
58004
+ "selectSource"
58005
+ ]);
58006
+ /** A send result, or `not-routed`: the role is not bound, so the native cap answers. */
58007
+ var RemoteMediaCommandResultSchema = discriminatedUnion("status", [...RemoteSendResultSchema.options, object({ status: literal("not-routed") })]);
58008
+ var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status: literal("saved") }), object({
58009
+ status: literal("refused"),
58010
+ reason: _enum(["unknown-template", "not-a-media-player"]),
58011
+ detail: string()
58012
+ })]);
58013
+ var deviceInput = object({ deviceId: number().int().nonnegative() });
58014
+ DeviceType.MediaPlayer;
58015
+ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
58016
+ kind: "mutation",
58017
+ auth: "admin"
58018
+ }), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
58019
+ role: RemoteRoleSchema,
58020
+ /** Sends in a row (volume steps). */
58021
+ repeat: number().int().min(1).max(50).default(1)
58022
+ }), RemoteSendResultSchema, {
58023
+ kind: "mutation",
58024
+ auth: "protected"
58025
+ }), method(deviceInput.extend({
58026
+ command: RemoteMediaCommandSchema,
58027
+ muted: boolean().optional(),
58028
+ source: string().optional(),
58029
+ repeat: number().int().min(1).max(50).default(1)
58030
+ }), RemoteMediaCommandResultSchema, {
58031
+ kind: "mutation",
58032
+ auth: "protected"
58033
+ });
58034
+ var TemplateKindSchema = _enum(["remote"]);
58035
+ /**
58036
+ * template — the generic store of reusable, named operator data (D963). A
58037
+ * record is `{ id, kind, name, payload }`; the kinds (today only `remote`, the
58038
+ * button grid of a remote) and the schema each payload must satisfy are
58039
+ * declared by the system in `template-kinds.ts`. Nothing here is specific to a
58040
+ * kind: the engine validates a payload against its kind's schema and, on a
58041
+ * delete, asks the kind's owner whether anything still points at the record.
58042
+ *
58043
+ * Every refusal is a typed result — a UI says "unknown kind" or names the
58044
+ * devices that still use a template, without parsing text.
58045
+ */
58046
+ var TemplateRecordSchema = object({
58047
+ id: string().min(1),
58048
+ kind: TemplateKindSchema,
58049
+ name: string().min(1).max(120),
58050
+ /** Shaped by the kind; `checkTemplatePayload(kind, payload)` reads it. */
58051
+ payload: unknown(),
58052
+ createdAt: number(),
58053
+ updatedAt: number()
58054
+ });
58055
+ var TemplateWriteResultSchema = discriminatedUnion("status", [object({
58056
+ status: literal("saved"),
58057
+ template: TemplateRecordSchema
58058
+ }), object({
58059
+ status: literal("refused"),
58060
+ reason: _enum(["invalid-payload", "not-found"]),
58061
+ detail: string()
58062
+ })]);
58063
+ /** A device still pointing at a template. */
58064
+ var TemplateUserSchema = object({
58065
+ deviceId: number().int().nonnegative(),
58066
+ name: string()
58067
+ });
58068
+ var TemplateDeleteResultSchema = discriminatedUnion("status", [
58069
+ object({ status: literal("deleted") }),
58070
+ object({ status: literal("not-found") }),
58071
+ object({
58072
+ status: literal("in-use"),
58073
+ devices: array(TemplateUserSchema).min(1)
58074
+ })
58075
+ ]);
58076
+ method(object({ kind: TemplateKindSchema.optional() }), array(TemplateRecordSchema), { auth: "protected" }), method(object({ id: string().min(1) }), TemplateRecordSchema.nullable(), { auth: "protected" }), method(object({
58077
+ kind: TemplateKindSchema,
58078
+ name: string().min(1).max(120),
58079
+ payload: unknown()
58080
+ }), TemplateWriteResultSchema, {
58081
+ kind: "mutation",
58082
+ auth: "admin"
58083
+ }), method(object({
58084
+ id: string().min(1),
58085
+ name: string().min(1).max(120).optional(),
58086
+ payload: unknown().optional()
58087
+ }), TemplateWriteResultSchema, {
58088
+ kind: "mutation",
58089
+ auth: "admin"
58090
+ }), method(object({ id: string().min(1) }), TemplateDeleteResultSchema, {
58091
+ kind: "mutation",
58092
+ auth: "admin"
58093
+ });
57751
58094
  DeviceType.Button, method(object({ deviceId: number().int().nonnegative() }), _void(), {
57752
58095
  kind: "mutation",
57753
58096
  auth: "protected"
@@ -60497,9 +60840,35 @@ var MediaInfoSchema = object({
60497
60840
  /** Optional cover-art / thumbnail URL. */
60498
60841
  imageUrl: string().optional()
60499
60842
  });
60843
+ /**
60844
+ * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
60845
+ * the device said so. `assumed`: the driver has no feedback (infrared) and
60846
+ * tracks what it last SENT; it moves only after a send was accepted, and a
60847
+ * human at the real remote makes it wrong. A UI shows an assumed value as a
60848
+ * guess, never as a reading.
60849
+ */
60850
+ var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
60851
+ /** The fields of a media-player status a driver can only guess. */
60852
+ var MediaPlayerAssumedFieldSchema = _enum([
60853
+ "state",
60854
+ "volumeLevel",
60855
+ "isMuted",
60856
+ "source"
60857
+ ]);
60500
60858
  object({
60501
60859
  /** Playback lifecycle state. */
60502
60860
  state: MediaPlayerStateSchema,
60861
+ /**
60862
+ * Whether the state fields are readings or the driver's own bookkeeping.
60863
+ * A slice written before this field existed parses as `reported`.
60864
+ */
60865
+ stateSource: MediaPlayerStateSourceSchema.default("reported"),
60866
+ /**
60867
+ * Which fields are the driver's own guess. `stateSource` is `assumed` when
60868
+ * this is not empty; a field not listed here is a reading even then (power
60869
+ * from a running-state source, mute guessed from the last send).
60870
+ */
60871
+ assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
60503
60872
  /** Volume as 0..100 inclusive. Null when the device has no volume
60504
60873
  * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
60505
60874
  volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -61940,6 +62309,14 @@ object({
61940
62309
  feedSound: boolean(),
61941
62310
  /** Speaker / prompt volume level (device-scaled integer). */
61942
62311
  volume: number().meta(readingMeta("none")),
62312
+ /** Portion (grams) of the last manual feed sent from a single-hopper
62313
+ * stepper — the default the next manual feed starts from. Persisted per
62314
+ * device by the provider; null until a manual feed has been sent. */
62315
+ lastFeedGrams: gramsPortion.nullable(),
62316
+ /** Hopper-1 portion of the last manual feed (dual-hopper); null until sent. */
62317
+ lastFeedHopper1: gramsPortion.nullable(),
62318
+ /** Hopper-2 portion of the last manual feed (dual-hopper); null until sent. */
62319
+ lastFeedHopper2: gramsPortion.nullable(),
61943
62320
  /** Ms epoch when the slice was last refreshed from the cloud. */
61944
62321
  lastFetchedAt: number()
61945
62322
  });
@@ -66683,9 +67060,17 @@ var trainingCapability = {
66683
67060
  })
66684
67061
  }
66685
67062
  };
67063
+ discriminatedUnion("kind", [object({
67064
+ kind: literal("raw"),
67065
+ timings: array(number().int()),
67066
+ settings: TransmitSettingsSchema.optional()
67067
+ }), object({
67068
+ kind: literal("pronto"),
67069
+ code: string()
67070
+ })]);
66686
67071
  DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
66687
67072
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
66688
- 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;
67073
+ 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;
66689
67074
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
66690
67075
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
66691
67076
  new Set(CAP_NAMES);
@@ -74427,6 +74812,41 @@ Object.freeze({
74427
74812
  access: "create",
74428
74813
  role: "admin"
74429
74814
  },
74815
+ "remote.getConfig": {
74816
+ capName: "remote",
74817
+ capScope: "system",
74818
+ addonId: null,
74819
+ access: "view",
74820
+ role: "admin"
74821
+ },
74822
+ "remote.listCommands": {
74823
+ capName: "remote",
74824
+ capScope: "system",
74825
+ addonId: null,
74826
+ access: "view",
74827
+ role: "admin"
74828
+ },
74829
+ "remote.sendCommand": {
74830
+ capName: "remote",
74831
+ capScope: "system",
74832
+ addonId: null,
74833
+ access: "create",
74834
+ role: "admin"
74835
+ },
74836
+ "remote.sendMediaCommand": {
74837
+ capName: "remote",
74838
+ capScope: "system",
74839
+ addonId: null,
74840
+ access: "create",
74841
+ role: "admin"
74842
+ },
74843
+ "remote.setConfig": {
74844
+ capName: "remote",
74845
+ capScope: "system",
74846
+ addonId: null,
74847
+ access: "create",
74848
+ role: "admin"
74849
+ },
74430
74850
  "runningState.getStatus": {
74431
74851
  capName: "running-state",
74432
74852
  capScope: "device",
@@ -75617,6 +76037,41 @@ Object.freeze({
75617
76037
  access: "view",
75618
76038
  role: "viewer"
75619
76039
  },
76040
+ "template.create": {
76041
+ capName: "template",
76042
+ capScope: "system",
76043
+ addonId: null,
76044
+ access: "create",
76045
+ role: "admin"
76046
+ },
76047
+ "template.delete": {
76048
+ capName: "template",
76049
+ capScope: "system",
76050
+ addonId: null,
76051
+ access: "delete",
76052
+ role: "admin"
76053
+ },
76054
+ "template.get": {
76055
+ capName: "template",
76056
+ capScope: "system",
76057
+ addonId: null,
76058
+ access: "view",
76059
+ role: "admin"
76060
+ },
76061
+ "template.list": {
76062
+ capName: "template",
76063
+ capScope: "system",
76064
+ addonId: null,
76065
+ access: "view",
76066
+ role: "admin"
76067
+ },
76068
+ "template.update": {
76069
+ capName: "template",
76070
+ capScope: "system",
76071
+ addonId: null,
76072
+ access: "create",
76073
+ role: "admin"
76074
+ },
75620
76075
  "terminalSession.adoptLegacyMonitor": {
75621
76076
  capName: "terminal-session",
75622
76077
  capScope: "system",
@@ -80448,6 +80903,7 @@ var SYSTEM_CAP_VOCABULARY = {
80448
80903
  "recording-archive": system(STORAGE),
80449
80904
  "recording-export": system("recording exports — requested from the timeline, not an automation step"),
80450
80905
  records: system(INTERNAL),
80906
+ remote: system("the per-device remote setup — authored in the Customize remote editor, sent through the remote UI"),
80451
80907
  "server-management": system(CLUSTER),
80452
80908
  "settings-store": system(INTERNAL),
80453
80909
  "smtp-provider": system(INTERNAL),
@@ -80460,6 +80916,7 @@ var SYSTEM_CAP_VOCABULARY = {
80460
80916
  "storage-provider": system(STORAGE),
80461
80917
  "stream-broker": system(PIPELINE),
80462
80918
  system: system(CLUSTER),
80919
+ template: system("operator-authored templates — edited in their own editor, never actuated"),
80463
80920
  "terminal-session": system(CLUSTER),
80464
80921
  toast: system(UI_PLUMBING),
80465
80922
  training: system(ML),
@@ -82886,6 +83343,31 @@ Object.freeze({
82886
83343
  form: "single",
82887
83344
  optional: true
82888
83345
  }],
83346
+ "remote.getConfig": [{
83347
+ name: "deviceId",
83348
+ form: "single",
83349
+ optional: false
83350
+ }],
83351
+ "remote.listCommands": [{
83352
+ name: "deviceId",
83353
+ form: "single",
83354
+ optional: false
83355
+ }],
83356
+ "remote.sendCommand": [{
83357
+ name: "deviceId",
83358
+ form: "single",
83359
+ optional: false
83360
+ }],
83361
+ "remote.sendMediaCommand": [{
83362
+ name: "deviceId",
83363
+ form: "single",
83364
+ optional: false
83365
+ }],
83366
+ "remote.setConfig": [{
83367
+ name: "deviceId",
83368
+ form: "single",
83369
+ optional: false
83370
+ }],
82889
83371
  "runningState.getStatus": [{
82890
83372
  name: "deviceId",
82891
83373
  form: "single",
@@ -84694,14 +85176,6 @@ DEFAULT_NATIVE_LEASE_SETTINGS.admission;
84694
85176
  String.raw`(?<=^|["'(\s>,\[{])`;
84695
85177
  var MB = 1024 * 1024;
84696
85178
  1024 * MB, 3072 * MB;
84697
- discriminatedUnion("kind", [object({
84698
- kind: literal("raw"),
84699
- timings: array(number().int()),
84700
- settings: TransmitSettingsSchema.optional()
84701
- }), object({
84702
- kind: literal("pronto"),
84703
- code: string()
84704
- })]);
84705
85179
  object({
84706
85180
  manufacturer: string().optional(),
84707
85181
  supportedModels: array(string()).optional(),