@camstack/ui-library 1.2.368 → 1.2.370

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/index.js CHANGED
@@ -5,7 +5,7 @@ import * as __mfHostReact from "react";
5
5
  import React, { Fragment, Suspense, cloneElement, createContext, createElement, forwardRef, lazy, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
6
6
  import * as __mfHostReactJsxRuntime from "react/jsx-runtime";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
- import { ALL_CAPABILITY_DEFINITIONS, CAM_PROFILE_ORDER, CLIP_STILL_DISPOSITION_HEADER, CLIP_STILL_REASON_CODE_HEADER, CLIP_STILL_REASON_HEADER, COMPOSER_ADDON_ID, CONTAINER_CHILD_PRIORITY, ConsumableLevelSchema, DEFAULT_DISPLAY_PREFERENCE, DEFAULT_EVENTS_BAND_BUFFER_SEC, DEVICE_HISTORY_ENERGY_KEY, DEVICE_HISTORY_QUERY_MANY_MAX_ITEMS, DEVICE_TYPE_CONTROL_KIND, DISPLAY_PREFERENCES, DeviceExportStatusSchema, DeviceFeature, DeviceRole, DeviceType, EXTENSION_SLOTS, EXTENSION_SLOT_IDS, EventCategory, ExportEntityKindSchema, ExposedDeviceSchema, ExposedEntitySchema, FIRST_LEVEL_MACRO_CLASSES, HISTORY_CATALOG, ICON_CATEGORIES, KNOWN_CAP_NAMES, MAX_SENSOR_TRIGGER_DEVICES, MODEL_PROVIDER_IDS, NAVIGATION_LIGHT_LEVEL_MAX, NAVIGATION_LIGHT_LEVEL_MIN, NODE_COLOR_IDS, NodeColorIdSchema, PALETTE_ENTRY_IDS, PET_FEEDER_MANUAL_FEED_MAX, PET_FEEDER_MANUAL_FEED_MIN, QUANTITY_BASE, RECORDING_AUDIO_TRIGGER_OFFERED_DBFS, RECORDING_SOURCE_CAMSTACK_ADDON, REDACTED_SECRET, RecordingConfigSchema, RecordingStatusSchema, SECRET_CLEAR, SOURCE_CAP_ACTIVE_FIELD, STATIONARY_OVERLAY_STYLE, SUBJECT_PATH_DWELL_EPS, SUBJECT_PATH_FULL_FRAME_COVERAGE, SUBJECT_PATH_MAX_POINTS, TIMEZONES, USE_ROOT_MODEL_SETTING_KEY, assignNodeColorId, assignNodeColorId as assignNodeColorId$1, baseUnitForQuantity, baseUnitOf, buildModelVariantGroups, buildSubjectPath, bundledCamstack, canConvertUnit, canonicalIconKey, clearModelBoundOverrides, clearModelBoundSetting, clusterStepSettingFieldsFor, collectModelBoundKeys, consumableFormOf, consumableKindOf, convertQuantityInput, coreBlockComposition, createDeviceProxy, createLazyTrpcSource, createSliceHandle, dehydrateSchema, deriveRecordingMode, describeModelVariant, displayUnitFor, effectiveStepSettings, findTimezone, formatParkedFor, formatReading, hasModelBoundOverrides, iconCategoryLabel, iconsInCategory, isDrawableSubjectPath, isKeychainStoredField, isModelScopedStepSettingKey, isReadingQuantity, isRootSuppliableStepId, isSecretClear, isSecretFieldView, isSecretMarker, lockDoorLinkOfComposition, modelBindingKey, normalizeUnit, paintHex, parseOccupancyScope, projectSubjectPath, publicEventCategories, resolveContainerPrimaryChild, resolveDeviceControlKind, resolveIconKey, resolveModelBoundSetting, resolveRecordingProfiles, resolveRootSupply, resolveVariantModelId, resolveViewableDeviceIds, searchIcons, selectAssignedProfileSlots, stepSettingSource, subjectPathSampleFromBox, subjectPathSvgPoints, tryConvertUnit, unitDimension, unitsForDimension, unitsForQuantity, withFieldFrom, withoutField, writeModelBoundSetting } from "@camstack/types";
8
+ import { ALL_CAPABILITY_DEFINITIONS, CAM_PROFILE_ORDER, CLIP_STILL_DISPOSITION_HEADER, CLIP_STILL_REASON_CODE_HEADER, CLIP_STILL_REASON_HEADER, COMPOSER_ADDON_ID, CONTAINER_CHILD_PRIORITY, ConsumableLevelSchema, DEFAULT_DISPLAY_PREFERENCE, DEFAULT_EVENTS_BAND_BUFFER_SEC, DEVICE_HISTORY_ENERGY_KEY, DEVICE_HISTORY_QUERY_MANY_MAX_ITEMS, DEVICE_TYPE_CONTROL_KIND, DISPLAY_PREFERENCES, DeviceExportStatusSchema, DeviceFeature, DeviceRole, DeviceType, EXTENSION_SLOTS, EXTENSION_SLOT_IDS, EventCategory, ExportEntityKindSchema, ExposedDeviceSchema, ExposedEntitySchema, FIRST_LEVEL_MACRO_CLASSES, HISTORY_CATALOG, ICON_CATEGORIES, KNOWN_CAP_NAMES, MAX_SENSOR_TRIGGER_DEVICES, MODEL_PROVIDER_IDS, NAVIGATION_LIGHT_LEVEL_MAX, NAVIGATION_LIGHT_LEVEL_MIN, NODE_COLOR_IDS, NodeColorIdSchema, PALETTE_ENTRY_IDS, PET_FEEDER_MANUAL_FEED_MAX, PET_FEEDER_MANUAL_FEED_MIN, QUANTITY_BASE, RECORDING_AUDIO_TRIGGER_OFFERED_DBFS, RECORDING_SOURCE_CAMSTACK_ADDON, REDACTED_SECRET, RecordingConfigSchema, RecordingStatusSchema, SECRET_CLEAR, SOURCE_CAP_ACTIVE_FIELD, STATIONARY_OVERLAY_STYLE, SUBJECT_PATH_DWELL_EPS, SUBJECT_PATH_FULL_FRAME_COVERAGE, SUBJECT_PATH_MAX_POINTS, TIMED_RUN_LIMITS, TIMEZONES, USE_ROOT_MODEL_SETTING_KEY, assignNodeColorId, assignNodeColorId as assignNodeColorId$1, baseUnitForQuantity, baseUnitOf, buildModelVariantGroups, buildSubjectPath, bundledCamstack, canConvertUnit, canonicalIconKey, clearModelBoundOverrides, clearModelBoundSetting, clusterStepSettingFieldsFor, collectModelBoundKeys, consumableFormOf, consumableKindOf, convertQuantityInput, coreBlockComposition, createDeviceProxy, createLazyTrpcSource, createSliceHandle, dehydrateSchema, deriveRecordingMode, describeModelVariant, displayUnitFor, effectiveStepSettings, findTimezone, formatParkedFor, formatReading, hasModelBoundOverrides, iconCategoryLabel, iconsInCategory, isDrawableSubjectPath, isKeychainStoredField, isModelScopedStepSettingKey, isReadingQuantity, isRootSuppliableStepId, isSecretClear, isSecretFieldView, isSecretMarker, lockDoorLinkOfComposition, modelBindingKey, normalizeUnit, paintHex, parseOccupancyScope, projectSubjectPath, publicEventCategories, resolveContainerPrimaryChild, resolveDeviceControlKind, resolveIconKey, resolveModelBoundSetting, resolveRecordingProfiles, resolveRootSupply, resolveVariantModelId, resolveViewableDeviceIds, searchIcons, selectAssignedProfileSlots, stepSettingSource, subjectPathSampleFromBox, subjectPathSvgPoints, tryConvertUnit, unitDimension, unitsForDimension, unitsForQuantity, withFieldFrom, withoutField, writeModelBoundSetting } from "@camstack/types";
9
9
  import * as __mfHostTrpcReactQuery from "@trpc/react-query";
10
10
  import { createTRPCReact } from "@trpc/react-query";
11
11
  import * as __mfHostReactDOM from "react-dom";
@@ -4260,6 +4260,34 @@ var Thermometer = createLucideIcon("thermometer", [["path", {
4260
4260
  * This source code is licensed under the ISC license.
4261
4261
  * See the LICENSE file in the root directory of this source tree.
4262
4262
  */
4263
+ var TimerOff = createLucideIcon("timer-off", [
4264
+ ["path", {
4265
+ d: "M10 2h4",
4266
+ key: "n1abiw"
4267
+ }],
4268
+ ["path", {
4269
+ d: "M4.6 11a8 8 0 0 0 1.7 8.7 8 8 0 0 0 8.7 1.7",
4270
+ key: "10he05"
4271
+ }],
4272
+ ["path", {
4273
+ d: "M7.4 7.4a8 8 0 0 1 10.3 1 8 8 0 0 1 .9 10.2",
4274
+ key: "15f7sh"
4275
+ }],
4276
+ ["path", {
4277
+ d: "m2 2 20 20",
4278
+ key: "1ooewy"
4279
+ }],
4280
+ ["path", {
4281
+ d: "M12 12v-2",
4282
+ key: "fwoke6"
4283
+ }]
4284
+ ]);
4285
+ /**
4286
+ * @license lucide-react v0.576.0 - ISC
4287
+ *
4288
+ * This source code is licensed under the ISC license.
4289
+ * See the LICENSE file in the root directory of this source tree.
4290
+ */
4263
4291
  var Timer = createLucideIcon("timer", [
4264
4292
  ["line", {
4265
4293
  x1: "10",
@@ -5432,6 +5460,11 @@ var DEVICE_TYPE_META = {
5432
5460
  labelKey: "uiLibrary.deviceMeta.type.petFountain",
5433
5461
  labelFallback: "Pet fountain"
5434
5462
  },
5463
+ [DeviceType.Heater]: {
5464
+ icon: Flame,
5465
+ labelKey: "uiLibrary.deviceMeta.type.heater",
5466
+ labelFallback: "Heater"
5467
+ },
5435
5468
  [DeviceType.Dishwasher]: {
5436
5469
  icon: Waves,
5437
5470
  labelKey: "uiLibrary.deviceMeta.type.dishwasher",
@@ -5937,7 +5970,7 @@ function lucideExportName(key) {
5937
5970
  function loadIconGlyphs() {
5938
5971
  if (fullTable !== void 0) return Promise.resolve();
5939
5972
  if (failure$1 !== void 0) return Promise.reject(failure$1);
5940
- pending ??= import("./icons-CZwJd50b.js").then((module) => {
5973
+ pending ??= import("./icons-e-xohmFb.js").then((module) => {
5941
5974
  fullTable = module;
5942
5975
  publish();
5943
5976
  }, (error) => {
@@ -6019,6 +6052,7 @@ function matchesCombo(event, combo, platform) {
6019
6052
  var PAGE_SCOPE = "page";
6020
6053
  /** Asked last, after the page: a global handler that yields to whatever the page registers. */
6021
6054
  var FALLBACK_SCOPE = "fallback";
6055
+ var NO_HOTKEYS = [];
6022
6056
  var RegistryContext = createContext(null);
6023
6057
  var ScopeContext = createContext(PAGE_SCOPE);
6024
6058
  function isTypingTarget(target) {
@@ -6057,32 +6091,49 @@ function HotkeyProvider({ children, platform }) {
6057
6091
  scopes: []
6058
6092
  });
6059
6093
  const effectivePlatform = platform ?? detectPlatform();
6060
- const registry = useMemo(() => ({
6061
- addBinding: (binding) => {
6062
- stateRef.current = {
6063
- ...stateRef.current,
6064
- bindings: [...stateRef.current.bindings, binding]
6065
- };
6066
- return () => {
6094
+ const listenersRef = useRef(/* @__PURE__ */ new Set());
6095
+ const listRef = useRef(NO_HOTKEYS);
6096
+ const registry = useMemo(() => {
6097
+ const publish = () => {
6098
+ listRef.current = distinctHotkeys(stateRef.current.bindings);
6099
+ for (const listener of listenersRef.current) listener();
6100
+ };
6101
+ return {
6102
+ subscribe: (listener) => {
6103
+ listenersRef.current = new Set([...listenersRef.current, listener]);
6104
+ return () => {
6105
+ listenersRef.current = new Set([...listenersRef.current].filter((l) => l !== listener));
6106
+ };
6107
+ },
6108
+ snapshot: () => listRef.current,
6109
+ addBinding: (binding) => {
6067
6110
  stateRef.current = {
6068
6111
  ...stateRef.current,
6069
- bindings: stateRef.current.bindings.filter((b) => b.id !== binding.id)
6112
+ bindings: [...stateRef.current.bindings, binding]
6070
6113
  };
6071
- };
6072
- },
6073
- addScope: (scope) => {
6074
- stateRef.current = {
6075
- ...stateRef.current,
6076
- scopes: [...stateRef.current.scopes, scope]
6077
- };
6078
- return () => {
6114
+ publish();
6115
+ return () => {
6116
+ stateRef.current = {
6117
+ ...stateRef.current,
6118
+ bindings: stateRef.current.bindings.filter((b) => b.id !== binding.id)
6119
+ };
6120
+ publish();
6121
+ };
6122
+ },
6123
+ addScope: (scope) => {
6079
6124
  stateRef.current = {
6080
6125
  ...stateRef.current,
6081
- scopes: stateRef.current.scopes.filter((s) => s !== scope)
6126
+ scopes: [...stateRef.current.scopes, scope]
6082
6127
  };
6083
- };
6084
- }
6085
- }), []);
6128
+ return () => {
6129
+ stateRef.current = {
6130
+ ...stateRef.current,
6131
+ scopes: stateRef.current.scopes.filter((s) => s !== scope)
6132
+ };
6133
+ };
6134
+ }
6135
+ };
6136
+ }, []);
6086
6137
  useEffect(() => {
6087
6138
  const onKeyDown = (event) => dispatch(stateRef.current, event, effectivePlatform);
6088
6139
  window.addEventListener("keydown", onKeyDown, true);
@@ -6094,6 +6145,29 @@ function HotkeyProvider({ children, platform }) {
6094
6145
  });
6095
6146
  }
6096
6147
  var nextBindingId = 0;
6148
+ function distinctHotkeys(bindings) {
6149
+ const seen = /* @__PURE__ */ new Map();
6150
+ for (const b of bindings) {
6151
+ const key = `${b.scope}|${b.combo}`;
6152
+ const prev = seen.get(key);
6153
+ if (!prev || prev.label === null && b.label !== null) seen.set(key, {
6154
+ combo: b.combo,
6155
+ scope: b.scope,
6156
+ label: b.label
6157
+ });
6158
+ }
6159
+ return [...seen.values()];
6160
+ }
6161
+ /**
6162
+ * The bindings registered below the `HotkeyProvider` right now (read-only; there
6163
+ * is no rebinding). Empty without a provider.
6164
+ */
6165
+ function useRegisteredHotkeys() {
6166
+ const registry = useContext(RegistryContext);
6167
+ return useSyncExternalStore(registry ? registry.subscribe : noSubscribe, registry ? registry.snapshot : emptySnapshot);
6168
+ }
6169
+ var noSubscribe = () => () => void 0;
6170
+ var emptySnapshot = () => NO_HOTKEYS;
6097
6171
  /**
6098
6172
  * Bind a combo for the life of the component. Without a `HotkeyProvider` above
6099
6173
  * it does nothing, so the browser keeps its own shortcut.
@@ -6113,6 +6187,7 @@ function useHotkey(combo, handler, options = {}) {
6113
6187
  return registry.addBinding({
6114
6188
  id: nextBindingId,
6115
6189
  combo,
6190
+ label: options.label ?? null,
6116
6191
  scope,
6117
6192
  handlerRef,
6118
6193
  preventDefault,
@@ -6124,7 +6199,8 @@ function useHotkey(combo, handler, options = {}) {
6124
6199
  combo,
6125
6200
  scope,
6126
6201
  preventDefault,
6127
- allowInInput
6202
+ allowInInput,
6203
+ options.label
6128
6204
  ]);
6129
6205
  }
6130
6206
  /** Bindings made below this component belong to `id`; while enabled it is the topmost scope. */
@@ -6169,11 +6245,13 @@ function useSearchFieldHotkey(ref, options = {}) {
6169
6245
  };
6170
6246
  useHotkey("mod+f", focusField, {
6171
6247
  enabled,
6172
- scope
6248
+ scope,
6249
+ label: "Focus the search field"
6173
6250
  });
6174
6251
  useHotkey("mod+k", focusField, {
6175
6252
  enabled,
6176
- scope
6253
+ scope,
6254
+ label: "Focus the search field"
6177
6255
  });
6178
6256
  }
6179
6257
  //#endregion
@@ -11454,6 +11532,10 @@ var useDisplayPaletteGetPalette = /*#__PURE__*/ alias(() => trpc.displayPalette.
11454
11532
  var useDisplayPaletteListPresets = /*#__PURE__*/ alias(() => trpc.displayPalette.listPresets.useQuery);
11455
11533
  /** Generated alias around `trpc.displayPalette.setPalette.useMutation`. */
11456
11534
  var useDisplayPaletteSetPalette = /*#__PURE__*/ alias(() => trpc.displayPalette.setPalette.useMutation);
11535
+ /** Generated alias around `trpc.doNotDisturb.setEnabled.useMutation`. */
11536
+ var useDoNotDisturbSetEnabled = /*#__PURE__*/ alias(() => trpc.doNotDisturb.setEnabled.useMutation);
11537
+ /** Generated alias around `trpc.doNotDisturb.getStatus.useQuery`. */
11538
+ var useDoNotDisturbGetStatus = /*#__PURE__*/ alias(() => trpc.doNotDisturb.getStatus.useQuery);
11457
11539
  /** Generated alias around `trpc.doorbell.getStatus.useQuery`. */
11458
11540
  var useDoorbellGetStatus = /*#__PURE__*/ alias(() => trpc.doorbell.getStatus.useQuery);
11459
11541
  /** Generated alias around `trpc.enumSensor.getStatus.useQuery`. */
@@ -11502,6 +11584,14 @@ var useFanControlSetDirection = /*#__PURE__*/ alias(() => trpc.fanControl.setDir
11502
11584
  var useFanControlSetOscillating = /*#__PURE__*/ alias(() => trpc.fanControl.setOscillating.useMutation);
11503
11585
  /** Generated alias around `trpc.fanControl.getStatus.useQuery`. */
11504
11586
  var useFanControlGetStatus = /*#__PURE__*/ alias(() => trpc.fanControl.getStatus.useQuery);
11587
+ /** Generated alias around `trpc.fanPresets.getPresets.useQuery`. */
11588
+ var useFanPresetsGetPresets = /*#__PURE__*/ alias(() => trpc.fanPresets.getPresets.useQuery);
11589
+ /** Generated alias around `trpc.fanPresets.setPresets.useMutation`. */
11590
+ var useFanPresetsSetPresets = /*#__PURE__*/ alias(() => trpc.fanPresets.setPresets.useMutation);
11591
+ /** Generated alias around `trpc.fanPresets.applyPreset.useMutation`. */
11592
+ var useFanPresetsApplyPreset = /*#__PURE__*/ alias(() => trpc.fanPresets.applyPreset.useMutation);
11593
+ /** Generated alias around `trpc.fanPresets.capturePreset.useQuery`. */
11594
+ var useFanPresetsCapturePreset = /*#__PURE__*/ alias(() => trpc.fanPresets.capturePreset.useQuery);
11505
11595
  /** Generated alias around `trpc.featureProbe.getStatus.useQuery`. */
11506
11596
  var useFeatureProbeGetStatus = /*#__PURE__*/ alias(() => trpc.featureProbe.getStatus.useQuery);
11507
11597
  /** Generated alias around `trpc.flood.getStatus.useQuery`. */
@@ -13032,6 +13122,12 @@ var useTerminalSessionPullOutput = /*#__PURE__*/ alias(() => trpc.terminalSessio
13032
13122
  var useTerminalSessionWriteInput = /*#__PURE__*/ alias(() => trpc.terminalSession.writeInput.useMutation);
13033
13123
  /** Generated alias around `trpc.terminalSession.close.useMutation`. */
13034
13124
  var useTerminalSessionClose = /*#__PURE__*/ alias(() => trpc.terminalSession.close.useMutation);
13125
+ /** Generated alias around `trpc.timedRun.runFor.useMutation`. */
13126
+ var useTimedRunRunFor = /*#__PURE__*/ alias(() => trpc.timedRun.runFor.useMutation);
13127
+ /** Generated alias around `trpc.timedRun.cancel.useMutation`. */
13128
+ var useTimedRunCancel = /*#__PURE__*/ alias(() => trpc.timedRun.cancel.useMutation);
13129
+ /** Generated alias around `trpc.timedRun.getStatus.useQuery`. */
13130
+ var useTimedRunGetStatus = /*#__PURE__*/ alias(() => trpc.timedRun.getStatus.useQuery);
13035
13131
  /** Generated alias around `trpc.toast.onToast.useSubscription`. */
13036
13132
  var useToastOnToast = /*#__PURE__*/ alias(() => trpc.toast.onToast.useSubscription);
13037
13133
  /** Generated alias around `trpc.training.listBaseModels.useQuery`. */
@@ -30560,8 +30656,8 @@ function RecordingPanel({ deviceId }) {
30560
30656
  * `type:'widget'` ConfigField. `WidgetSlot` resolves these BEFORE the
30561
30657
  * Module-Federation `WidgetRegistry`. ids are namespaced `host/<name>`. */
30562
30658
  var HOST_WIDGETS = {
30563
- "host/motion-zones-grid": lazy(() => import("./MotionZonesSettings-dx3wObgK.js").then((m) => ({ default: m.MotionZonesSettings }))),
30564
- "host/privacy-mask-grid": lazy(() => import("./PrivacyMaskSettings-BM2C_xWz.js").then((m) => ({ default: m.PrivacyMaskSettings }))),
30659
+ "host/motion-zones-grid": lazy(() => import("./MotionZonesSettings-Zcfa5c9l.js").then((m) => ({ default: m.MotionZonesSettings }))),
30660
+ "host/privacy-mask-grid": lazy(() => import("./PrivacyMaskSettings-B_X42yzN.js").then((m) => ({ default: m.PrivacyMaskSettings }))),
30565
30661
  "host/ptz-panel": PtzPanel,
30566
30662
  "host/navigation-panel": NavigationPanel,
30567
30663
  "host/consumables-panel": ConsumablesPanel,
@@ -54120,6 +54216,137 @@ function PetFeederHeroCard({ trpc, deviceId, features, optimistic }) {
54120
54216
  });
54121
54217
  }
54122
54218
  //#endregion
54219
+ //#region src/composites/device-controls/timed-run-control.tsx
54220
+ /**
54221
+ * "Run for N" - the inline control of the `timed-run` cap (D993).
54222
+ *
54223
+ * A number, the unit it is in, and a Run button: the hub turns the device on and
54224
+ * switches it off again after that long. While a run is armed the control shows
54225
+ * the time left (counted down from the slice's `activeUntil`) and a Cancel. The
54226
+ * maximum is the device type's own bound (`TIMED_RUN_LIMITS`); a value above it
54227
+ * is refused by the hub with a typed reason, which this control says in words.
54228
+ *
54229
+ * Rendered only when the device binds `timed-run`. An unknown slice is "nothing
54230
+ * armed", never a running timer.
54231
+ */
54232
+ var TICK_MS = 1e3;
54233
+ var SECONDS_PER_MINUTE$1 = 60;
54234
+ var MS_PER_SECOND = 1e3;
54235
+ var DEFAULT_MINUTES = 30;
54236
+ var DEFAULT_SECONDS = 60;
54237
+ /** `m:ss` for a countdown; a started run never shows a negative time. */
54238
+ function formatCountdown(remainingMs) {
54239
+ const total = Math.max(0, Math.ceil(remainingMs / MS_PER_SECOND));
54240
+ const minutes = Math.floor(total / SECONDS_PER_MINUTE$1);
54241
+ const seconds = total % SECONDS_PER_MINUTE$1;
54242
+ return `${minutes}:${String(seconds).padStart(2, "0")}`;
54243
+ }
54244
+ /** The largest value the field accepts, in the limit's unit. */
54245
+ function maxInUnit(limit) {
54246
+ return limit.unit === "min" ? limit.maxSeconds / SECONDS_PER_MINUTE$1 : limit.maxSeconds;
54247
+ }
54248
+ function useNow(active) {
54249
+ const [now, setNow] = useState(() => Date.now());
54250
+ useEffect(() => {
54251
+ if (!active) return void 0;
54252
+ setNow(Date.now());
54253
+ const handle = setInterval(() => setNow(Date.now()), TICK_MS);
54254
+ return () => clearInterval(handle);
54255
+ }, [active]);
54256
+ return now;
54257
+ }
54258
+ function TimedRunControl({ trpc, deviceId, limit }) {
54259
+ const t = useUiText();
54260
+ const { cap, slice, online } = useDeviceCapability({
54261
+ trpc,
54262
+ deviceId,
54263
+ cap: (d) => d.timedRun,
54264
+ slice: (d) => d.state.timedRun
54265
+ });
54266
+ const max = maxInUnit(limit);
54267
+ const [draft, setDraft] = useState(Math.min(max, limit.unit === "min" ? DEFAULT_MINUTES : DEFAULT_SECONDS));
54268
+ const [refusal, setRefusal] = useState(null);
54269
+ const activeUntil = slice?.activeUntil ?? null;
54270
+ const now = useNow(activeUntil !== null);
54271
+ if (cap === void 0) return null;
54272
+ const unitLabel = limit.unit === "min" ? t("uiLibrary.timedRun.minutes", "min") : t("uiLibrary.timedRun.seconds", "s");
54273
+ const valid = Number.isFinite(draft) && draft > 0 && draft <= max;
54274
+ const armed = activeUntil !== null && activeUntil > now;
54275
+ const run = () => {
54276
+ if (!valid) return;
54277
+ setRefusal(null);
54278
+ cap.runFor({
54279
+ duration: draft,
54280
+ unit: limit.unit
54281
+ }).then((result) => {
54282
+ if (!result.ok) setRefusal(result.reason);
54283
+ });
54284
+ };
54285
+ return /* @__PURE__ */ jsxs("div", {
54286
+ className: "flex flex-col gap-1.5",
54287
+ "data-testid": "timed-run-control",
54288
+ children: [
54289
+ /* @__PURE__ */ jsxs("div", {
54290
+ className: "flex items-center gap-2",
54291
+ children: [
54292
+ /* @__PURE__ */ jsx(Input, {
54293
+ type: "number",
54294
+ inputMode: "numeric",
54295
+ min: 1,
54296
+ max,
54297
+ step: 1,
54298
+ value: Number.isFinite(draft) ? draft : "",
54299
+ disabled: !online,
54300
+ "aria-label": t("uiLibrary.timedRun.duration", "Run for"),
54301
+ className: "w-20 tabular-nums",
54302
+ onChange: (event) => setDraft(event.target.valueAsNumber)
54303
+ }),
54304
+ /* @__PURE__ */ jsx("span", {
54305
+ className: "text-xs text-foreground-muted",
54306
+ children: unitLabel
54307
+ }),
54308
+ /* @__PURE__ */ jsxs(Button, {
54309
+ size: "sm",
54310
+ disabled: !online || !valid,
54311
+ onClick: run,
54312
+ children: [/* @__PURE__ */ jsx(Timer, {
54313
+ className: "h-4 w-4",
54314
+ "aria-hidden": true
54315
+ }), t("uiLibrary.timedRun.run", "Run")]
54316
+ }),
54317
+ armed && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
54318
+ className: "text-xs font-medium tabular-nums text-foreground",
54319
+ "data-testid": "timed-run-countdown",
54320
+ children: t("uiLibrary.timedRun.remaining", "{{time}} left", { time: formatCountdown(activeUntil - now) })
54321
+ }), /* @__PURE__ */ jsx(Button, {
54322
+ size: "sm",
54323
+ variant: "outline",
54324
+ disabled: !online,
54325
+ "aria-label": t("uiLibrary.timedRun.cancel", "Cancel the timer"),
54326
+ onClick: () => void cap.cancel({}),
54327
+ children: /* @__PURE__ */ jsx(TimerOff, {
54328
+ className: "h-4 w-4",
54329
+ "aria-hidden": true
54330
+ })
54331
+ })] })
54332
+ ]
54333
+ }),
54334
+ !valid && /* @__PURE__ */ jsx("span", {
54335
+ className: "text-xs text-danger",
54336
+ children: t("uiLibrary.timedRun.range", "Enter 1 to {{max}} {{unit}}", {
54337
+ max,
54338
+ unit: unitLabel
54339
+ })
54340
+ }),
54341
+ refusal !== null && /* @__PURE__ */ jsx("span", {
54342
+ className: "text-xs text-danger",
54343
+ role: "alert",
54344
+ children: refusal === "over-max" ? t("uiLibrary.timedRun.overMax", "That is longer than this device may run.") : refusal === "command-failed" ? t("uiLibrary.timedRun.commandFailed", "The device did not turn on.") : t("uiLibrary.timedRun.unsupported", "This device cannot run on a timer.")
54345
+ })
54346
+ ]
54347
+ });
54348
+ }
54349
+ //#endregion
54123
54350
  //#region src/composites/device-controls/pet-fountain-panel.tsx
54124
54351
  /**
54125
54352
  * Pet-fountain controls for a `DeviceType.PetFountain` device.
@@ -54148,6 +54375,7 @@ var KEYFRAMES$2 = `
54148
54375
  .pfn-ripple, .pfn-bubble { animation: none !important; opacity: 0; }
54149
54376
  }
54150
54377
  `;
54378
+ var PUMP_LIMIT = TIMED_RUN_LIMITS[DeviceType.PetFountain];
54151
54379
  var LITRES_TO_ML = 1e3;
54152
54380
  var SECONDS_PER_MINUTE = 60;
54153
54381
  var MAX_PUMP_MINUTES = 240;
@@ -54312,6 +54540,11 @@ function PetFountainPanel({ trpc, deviceId, layout, optimistic }) {
54312
54540
  ]
54313
54541
  })
54314
54542
  }),
54543
+ PUMP_LIMIT !== void 0 && /* @__PURE__ */ jsx(TimedRunControl, {
54544
+ trpc,
54545
+ deviceId,
54546
+ limit: PUMP_LIMIT
54547
+ }),
54315
54548
  /* @__PURE__ */ jsxs(Button, {
54316
54549
  variant: "outline",
54317
54550
  size: "sm",
@@ -54536,1277 +54769,1430 @@ function PetFountainHeroCard({ trpc, deviceId, features, optimistic }) {
54536
54769
  });
54537
54770
  }
54538
54771
  //#endregion
54539
- //#region src/composites/device-controls/dishwasher-control.tsx
54540
- /**
54541
- * Dishwasher controls for a `DeviceType.Dishwasher` device.
54542
- *
54543
- * Reads the `dishwasher` cap status slice and renders inline + hero surfaces
54544
- * mirroring vacuum-control / pet-feeder patterns.
54545
- *
54546
- * Salt and rinse aid are not here: they are items of the device's `consumables`
54547
- * cap, shown by the page's Consumables section like every device's (D915).
54548
- *
54549
- * UNKNOWN IS NOT OFF. The slice carries `null` for everything the appliance has not
54550
- * reported, and this view renders that as "—" / a disabled control, never as an unchecked
54551
- * box or a zero. It also does not echo a command before the appliance confirms it: the
54552
- * slice moves when the appliance says so.
54553
- */
54554
- /** What the operation state is called to a person, and how it is toned. */
54555
- function dishwasherOperationMeta(operationState, t = defaultUiText) {
54556
- switch (operationState) {
54557
- case "Run": return {
54558
- label: t("uiLibrary.dishwasher.op.run", "Running"),
54559
- tone: "text-primary"
54560
- };
54561
- case "Pause": return {
54562
- label: t("uiLibrary.dishwasher.op.pause", "Paused"),
54563
- tone: "text-warning"
54564
- };
54565
- case "Finished": return {
54566
- label: t("uiLibrary.dishwasher.op.finished", "Finished"),
54567
- tone: "text-success"
54568
- };
54569
- case "Error": return {
54570
- label: t("uiLibrary.dishwasher.op.error", "Error"),
54571
- tone: "text-danger"
54572
- };
54573
- case "Aborting": return {
54574
- label: t("uiLibrary.dishwasher.op.aborting", "Stopping"),
54575
- tone: "text-warning"
54576
- };
54577
- case "ActionRequired": return {
54578
- label: t("uiLibrary.dishwasher.op.actionRequired", "Action required"),
54579
- tone: "text-warning"
54580
- };
54581
- case "DelayedStart": return {
54582
- label: t("uiLibrary.dishwasher.op.delayedStart", "Delayed start"),
54583
- tone: "text-primary"
54584
- };
54585
- case "Ready": return {
54586
- label: t("uiLibrary.dishwasher.op.ready", "Ready"),
54587
- tone: "text-foreground"
54588
- };
54589
- case "Inactive": return {
54590
- label: t("uiLibrary.dishwasher.op.inactive", "Inactive"),
54591
- tone: "text-foreground-subtle"
54592
- };
54593
- case null: return {
54594
- label: t("uiLibrary.dishwasher.unknown", "Unknown"),
54595
- tone: "text-foreground-subtle"
54596
- };
54597
- }
54772
+ //#region src/composites/device-controls/ac-panel.tsx
54773
+ /** Modes that mean the device can cool, dry, or move air — an air conditioner. */
54774
+ var COOLING_MODES = new Set([
54775
+ "cool",
54776
+ "heat_cool",
54777
+ "dry",
54778
+ "fan_only"
54779
+ ]);
54780
+ /** A heater offers heat (and maybe auto/off) and none of the cooling modes. */
54781
+ function climateOffersCooling(modes) {
54782
+ return modes.some((mode) => COOLING_MODES.has(mode));
54598
54783
  }
54599
- /** The headline for the whole slice: the appliance's state, or why there is none. */
54600
- function dishwasherHeadline(status, t = defaultUiText) {
54601
- switch (status.availability) {
54602
- case "offline": return {
54603
- label: t("uiLibrary.dishwasher.offline", "Offline"),
54604
- tone: "text-foreground-subtle"
54605
- };
54606
- case "description-missing": return {
54607
- label: t("uiLibrary.dishwasher.descriptionMissing", "Waiting for the appliance profile"),
54608
- tone: "text-warning"
54609
- };
54610
- case "available": return dishwasherOperationMeta(status.operationState, t);
54784
+ /** Setpoint track bounds. Absent when the integration did not report both ends. */
54785
+ function climateSetpointBounds(status) {
54786
+ const min = status.minTemp;
54787
+ const max = status.maxTemp;
54788
+ if (typeof min !== "number" || typeof max !== "number") return null;
54789
+ if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) return null;
54790
+ return {
54791
+ min,
54792
+ max
54793
+ };
54794
+ }
54795
+ /** Map a 0–1 drag fraction onto the setpoint, snapped to `tempStep`. */
54796
+ function climateTargetFromFraction(fraction, bounds, tempStep) {
54797
+ const step = resolveClimateTempStep(tempStep);
54798
+ const clamped = Math.min(1, Math.max(0, fraction));
54799
+ const raw = bounds.min + clamped * (bounds.max - bounds.min);
54800
+ const steps = Math.round((raw - bounds.min) / step);
54801
+ const snapped = bounds.min + steps * step;
54802
+ const rounded = Math.round(snapped * 1e3) / 1e3;
54803
+ return Math.min(bounds.max, Math.max(bounds.min, rounded));
54804
+ }
54805
+ /** AC-appropriate short mode labels. Exhaustive over HvacMode. */
54806
+ function modeLabel(t, mode) {
54807
+ switch (mode) {
54808
+ case "cool": return t("uiLibrary.acPanel.modeCool", "Cool");
54809
+ case "heat": return t("uiLibrary.acPanel.modeHeat", "Heat");
54810
+ case "auto": return t("uiLibrary.acPanel.modeAuto", "Auto");
54811
+ case "heat_cool": return t("uiLibrary.acPanel.modeHeatCool", "Heat·Cool");
54812
+ case "fan_only": return t("uiLibrary.acPanel.modeFan", "Fan");
54813
+ case "dry": return t("uiLibrary.acPanel.modeDry", "Dry");
54814
+ case "off": return t("uiLibrary.acPanel.modeOff", "Off");
54611
54815
  }
54612
54816
  }
54613
- /** Last segment of a feature key, spaced out: `Dishcare.Dishwasher.Program.Eco50` -> `Eco50`. */
54614
- function featureLabel(key) {
54615
- return (key.split(".").pop() ?? key).replace(/([a-z0-9])([A-Z])/g, "$1 $2");
54817
+ /** Per-mode icon (lucide). Exhaustive over HvacMode. */
54818
+ var MODE_ICON = {
54819
+ cool: Snowflake,
54820
+ heat: Flame,
54821
+ auto: Sparkles,
54822
+ heat_cool: Thermometer,
54823
+ fan_only: Fan,
54824
+ dry: Droplets,
54825
+ off: Power
54826
+ };
54827
+ /** Mode accent hex — drives the airflow particles, the glow, and the target
54828
+ * value colour. Mirrors the thermostat gauge palette. Exhaustive. */
54829
+ var MODE_ACCENT = {
54830
+ heat: "#f59e0b",
54831
+ cool: "#60a5fa",
54832
+ auto: "#c084fc",
54833
+ heat_cool: "#e879f9",
54834
+ fan_only: "#94a3b8",
54835
+ dry: "#22d3ee",
54836
+ off: "#a1a1aa"
54837
+ };
54838
+ /** Title-case a snake/lower token for a selector option ('medium_low' → 'Medium
54839
+ * low', 'turbo' → 'Turbo'). Shared by the fan + preset selectors. */
54840
+ function fanLabel(token) {
54841
+ const spaced = token.replace(/_/g, " ");
54842
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1);
54843
+ }
54844
+ /** Preset → icon. Unknown presets fall back to a neutral sparkle. */
54845
+ function presetIcon(preset) {
54846
+ switch (preset) {
54847
+ case "turbo": return Zap;
54848
+ case "quiet": return Feather;
54849
+ case "sleep": return Moon;
54850
+ case "eco": return Leaf;
54851
+ case "8c_heat": return Snowflake;
54852
+ case "none": return Ban;
54853
+ default: return Sparkles;
54854
+ }
54616
54855
  }
54617
54856
  /**
54618
- * Salt and rinse aid are consumable items (D915). Their events must not
54619
- * reappear on the hero — the Consumables section is the only surface.
54857
+ * Fan level → airflow animation period. Higher speed ⇒ shorter period. Unknown
54858
+ * strings fall back to a medium pace. Turbo (a preset) shortens it further.
54620
54859
  */
54621
- function isConsumableDishwasherEvent(event) {
54622
- const short = (event.split(".").pop() ?? event).toLowerCase();
54623
- return short.includes("salt") || short.includes("rinse");
54624
- }
54625
- /** Raised events the hero may name. Consumable events are dropped. */
54626
- function visibleDishwasherEvents(events) {
54627
- return events.filter((event) => !isConsumableDishwasherEvent(event));
54860
+ function airflowPeriodSec(fanMode) {
54861
+ switch (fanMode) {
54862
+ case "high": return 1;
54863
+ case "medium_high": return 1.3;
54864
+ case "medium": return 1.6;
54865
+ case "medium_low": return 1.9;
54866
+ case "low": return 2.2;
54867
+ default: return 1.8;
54868
+ }
54628
54869
  }
54629
- /** Whole seconds as a short duration: `1 h 24 min`, `42 min`, `30 s`. */
54630
- function formatDuration(seconds, t = defaultUiText) {
54631
- if (seconds < 60) return t("uiLibrary.dishwasher.durationSeconds", "{{n}} s", { n: seconds });
54632
- const minutes = Math.round(seconds / 60);
54633
- if (minutes < 60) return t("uiLibrary.dishwasher.durationMinutes", "{{n}} min", { n: minutes });
54634
- const hours = Math.floor(minutes / 60);
54635
- const rest = minutes % 60;
54636
- return rest === 0 ? t("uiLibrary.dishwasher.durationHours", "{{n}} h", { n: hours }) : t("uiLibrary.dishwasher.durationHoursMinutes", "{{h}} h {{m}} min", {
54637
- h: hours,
54638
- m: rest
54639
- });
54870
+ var KEYFRAMES$1 = `
54871
+ @keyframes acv-fall { 0%{transform:translateY(-1.75rem);opacity:0} 18%{opacity:.7} 82%{opacity:.7} 100%{transform:translateY(7.5rem);opacity:0} }
54872
+ @keyframes acv-rise { 0%{transform:translateY(7.5rem);opacity:0} 18%{opacity:.7} 82%{opacity:.7} 100%{transform:translateY(-1.75rem);opacity:0} }
54873
+ @keyframes acv-sway { 0%,100%{transform:translateX(-9%)} 50%{transform:translateX(9%)} }
54874
+ @keyframes acv-swing-h { 0%,100%{transform:translateX(-22%)} 50%{transform:translateX(22%)} }
54875
+ @keyframes acv-swing-v { 0%,100%{transform:translateY(-22%)} 50%{transform:translateY(22%)} }
54876
+ @keyframes acv-spin { to { transform:rotate(360deg) } }
54877
+ @keyframes acv-glow { 0%,100%{opacity:.35;transform:scale(1)} 50%{opacity:.6;transform:scale(1.06)} }
54878
+ @media (prefers-reduced-motion: reduce) {
54879
+ .acv-streak, .acv-fan, .acv-sway-wrap, .acv-glow, .acv-swing { animation: none !important; }
54640
54880
  }
54641
- function useDishwasher(trpc, deviceId) {
54642
- return useDeviceCapability({
54881
+ `;
54882
+ function AcPanel({ trpc, deviceId, layout, optimistic }) {
54883
+ const t = useUiText();
54884
+ const { cap, slice, available } = useDeviceCapability({
54643
54885
  trpc,
54644
54886
  deviceId,
54645
- cap: (d) => d.dishwasher,
54646
- slice: (d) => d.state.dishwasher
54647
- });
54648
- }
54649
- function DishwasherIconButton({ label, busy, active, onClick, children }) {
54650
- return /* @__PURE__ */ jsx("button", {
54651
- type: "button",
54652
- "aria-label": label,
54653
- title: label,
54654
- disabled: busy,
54655
- onClick: (e) => {
54656
- e.stopPropagation();
54657
- onClick();
54658
- },
54659
- className: cn("inline-flex h-5 w-5 items-center justify-center rounded text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors", active && "bg-primary text-primary-foreground", busy && "opacity-40 cursor-not-allowed"),
54660
- children
54661
- });
54662
- }
54663
- function DishwasherGraphic({ running, progressPercent }) {
54664
- const pct = progressPercent != null ? Math.max(0, Math.min(100, progressPercent)) : running ? 40 : 0;
54665
- return /* @__PURE__ */ jsxs("div", {
54666
- "aria-hidden": "true",
54667
- className: "relative w-28 h-36 rounded border-2 border-border bg-gradient-to-b from-surface-hover to-surface overflow-hidden flex-shrink-0",
54668
- children: [/* @__PURE__ */ jsx("div", {
54669
- className: cn("absolute inset-x-0 bottom-0 bg-primary/25 transition-[height] duration-500", running && "animate-pulse"),
54670
- style: { height: `${pct}%` }
54671
- }), /* @__PURE__ */ jsx("div", {
54672
- className: "absolute inset-0 flex items-center justify-center text-foreground-subtle",
54673
- children: /* @__PURE__ */ jsx(Waves, { className: "h-10 w-10 opacity-70" })
54674
- })]
54887
+ cap: (d) => d.climateControl,
54888
+ slice: (d) => d.state.climateControl
54675
54889
  });
54676
- }
54677
- function DishwasherPanel({ trpc, deviceId, layout }) {
54678
- const t = useUiText();
54679
- const { cap, slice, available } = useDishwasher(trpc, deviceId);
54890
+ const { display, applyOptimistic } = useOptimisticSlice(slice, { enabled: optimistic ?? true });
54680
54891
  if (cap === void 0) return null;
54681
- if (slice === void 0) return null;
54682
- const display = slice;
54683
- const link = display.availability === "available";
54684
- const busy = !available || !link;
54685
- const optionTogglesLocked = display.childLock === true;
54686
- const meta = dishwasherHeadline(display, t);
54687
- const running = display.operationState === "Run";
54688
- const paused = display.operationState === "Pause";
54689
- const startable = display.remoteStartAllowed === true && display.selectedProgram !== null;
54690
- const press = (fn) => {
54691
- if (busy) return;
54692
- fn();
54693
- };
54892
+ if (display === void 0) return null;
54893
+ const busy = !available;
54694
54894
  if (layout === "compact") return /* @__PURE__ */ jsxs("div", {
54695
- className: "inline-flex items-center gap-1.5 max-w-full",
54895
+ "data-mode": display.mode,
54896
+ className: "inline-flex items-center gap-1",
54696
54897
  children: [
54697
- display.doorOpen === true && /* @__PURE__ */ jsx("span", {
54698
- className: "inline-flex text-warning shrink-0",
54699
- title: t("uiLibrary.dishwasher.doorOpen", "Door open"),
54700
- "aria-label": t("uiLibrary.dishwasher.doorOpen", "Door open"),
54701
- children: /* @__PURE__ */ jsx(DoorOpen, { className: "h-3.5 w-3.5" })
54702
- }),
54703
54898
  /* @__PURE__ */ jsx("span", {
54704
- className: cn("text-xs font-medium tabular-nums shrink-0", meta.tone),
54705
- children: meta.label
54706
- }),
54707
- display.program != null && /* @__PURE__ */ jsx("span", {
54708
- className: "text-xs text-foreground-subtle truncate max-w-[7rem]",
54709
- title: display.program,
54710
- children: featureLabel(display.program)
54711
- }),
54712
- display.remaining != null && /* @__PURE__ */ jsxs("span", {
54713
- className: "inline-flex items-center gap-0.5 text-xs text-foreground-subtle tabular-nums shrink-0",
54714
- children: [/* @__PURE__ */ jsx(Timer, { className: "h-3 w-3" }), formatDuration(display.remaining, t)]
54715
- }),
54716
- /* @__PURE__ */ jsx(DishwasherIconButton, {
54717
- label: t("uiLibrary.dishwasher.start", "Start"),
54718
- busy: busy || !startable,
54719
- active: running,
54720
- onClick: () => press(() => cap.start({})),
54721
- children: /* @__PURE__ */ jsx(Play, { className: "h-3 w-3" })
54899
+ className: cn("text-xs tabular-nums font-medium", MODE_TEXT_COLOR[display.mode]),
54900
+ children: display.target !== null ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
54901
+ display.target,
54902
+ "°",
54903
+ display.currentTemp !== null && /* @__PURE__ */ jsxs("span", {
54904
+ className: "text-foreground-subtle font-normal",
54905
+ children: [
54906
+ " ",
54907
+ "(",
54908
+ display.currentTemp,
54909
+ "°)"
54910
+ ]
54911
+ })
54912
+ ] }) : display.currentTemp !== null ? /* @__PURE__ */ jsxs("span", {
54913
+ className: "text-foreground-subtle",
54914
+ children: [display.currentTemp, "°"]
54915
+ }) : null
54722
54916
  }),
54723
- /* @__PURE__ */ jsx(DishwasherIconButton, {
54724
- label: paused ? t("uiLibrary.dishwasher.resume", "Resume") : t("uiLibrary.dishwasher.pause", "Pause"),
54725
- busy: busy || !(running || paused),
54726
- active: paused,
54727
- onClick: () => press(() => paused ? cap.resume({}) : cap.pause({})),
54728
- children: /* @__PURE__ */ jsx(Pause, { className: "h-3 w-3" })
54917
+ display.target !== null && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
54918
+ type: "button",
54919
+ "aria-label": t("uiLibrary.acPanel.decrease", "Decrease target"),
54920
+ disabled: busy,
54921
+ onClick: (e) => {
54922
+ e.stopPropagation();
54923
+ if (!busy && display.target !== null) {
54924
+ const next = nextClimateTarget(display.target, -1, display);
54925
+ applyOptimistic({ target: next });
54926
+ cap.setTarget({ target: next });
54927
+ }
54928
+ },
54929
+ className: cn("inline-flex h-5 w-5 items-center justify-center rounded text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors text-xs", busy && "opacity-40 cursor-not-allowed"),
54930
+ children: "−"
54931
+ }), /* @__PURE__ */ jsx("button", {
54932
+ type: "button",
54933
+ "aria-label": t("uiLibrary.acPanel.increase", "Increase target"),
54934
+ disabled: busy,
54935
+ onClick: (e) => {
54936
+ e.stopPropagation();
54937
+ if (!busy && display.target !== null) {
54938
+ const next = nextClimateTarget(display.target, 1, display);
54939
+ applyOptimistic({ target: next });
54940
+ cap.setTarget({ target: next });
54941
+ }
54942
+ },
54943
+ className: cn("inline-flex h-5 w-5 items-center justify-center rounded text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors text-xs", busy && "opacity-40 cursor-not-allowed"),
54944
+ children: "+"
54945
+ })] }),
54946
+ /* @__PURE__ */ jsx("select", {
54947
+ "aria-label": t("uiLibrary.acPanel.mode", "Mode"),
54948
+ value: display.mode,
54949
+ disabled: busy,
54950
+ onChange: (e) => {
54951
+ e.stopPropagation();
54952
+ const mode = display.availableModes.find((m) => m === e.target.value);
54953
+ if (!busy && mode) {
54954
+ applyOptimistic({ mode });
54955
+ cap.setMode({ mode });
54956
+ }
54957
+ },
54958
+ className: cn("bg-transparent px-0.5 text-xs text-foreground-subtle hover:text-foreground cursor-pointer", busy && "opacity-40 cursor-not-allowed"),
54959
+ children: display.availableModes.map((m) => /* @__PURE__ */ jsx("option", {
54960
+ value: m,
54961
+ children: modeLabel(t, m)
54962
+ }, m))
54729
54963
  })
54730
54964
  ]
54731
54965
  });
54732
- const programs = display.availablePrograms;
54966
+ const accent = MODE_ACCENT[display.mode];
54967
+ const on = display.mode !== "off";
54968
+ const heatingOnly = !climateOffersCooling(display.availableModes);
54969
+ const setpointBounds = climateSetpointBounds(display);
54970
+ const CurrentPresetIcon = presetIcon(display.preset);
54971
+ const boost = display.preset === "turbo";
54972
+ const period = Math.max(.55, airflowPeriodSec(display.fanMode) * (boost ? .6 : 1));
54973
+ const showVSwing = display.swingVertical !== null;
54974
+ const showHSwing = display.swingHorizontal !== null;
54975
+ const swaying = on && (display.swingVertical === true || display.swingHorizontal === true);
54733
54976
  return /* @__PURE__ */ jsxs("div", {
54734
- className: "flex flex-col gap-3 rounded-lg border border-border bg-surface p-4",
54977
+ "data-mode": display.mode,
54978
+ className: cn("relative flex flex-col items-stretch gap-2.5 overflow-hidden rounded-lg border p-3 transition-colors", MODE_COLOR[display.mode]),
54735
54979
  children: [
54980
+ /* @__PURE__ */ jsx("style", { children: KEYFRAMES$1 }),
54736
54981
  /* @__PURE__ */ jsxs("div", {
54737
- className: "flex items-start gap-4",
54738
- children: [/* @__PURE__ */ jsx(DishwasherGraphic, {
54739
- running,
54740
- progressPercent: display.progress
54741
- }), /* @__PURE__ */ jsxs("div", {
54742
- className: "flex min-w-0 flex-1 flex-col gap-2",
54743
- children: [
54744
- /* @__PURE__ */ jsxs("div", {
54745
- className: "flex flex-wrap items-center gap-2",
54746
- children: [/* @__PURE__ */ jsx("span", {
54747
- className: cn("text-3xl font-semibold", meta.tone),
54748
- children: meta.label
54749
- }), display.powerOn === false && /* @__PURE__ */ jsx("span", {
54750
- className: "text-xs font-medium text-foreground-subtle",
54751
- children: t("uiLibrary.dishwasher.powerOff", "Power off")
54752
- })]
54753
- }),
54754
- display.program != null && /* @__PURE__ */ jsx("span", {
54755
- className: "text-sm text-foreground-subtle",
54756
- title: display.program,
54757
- children: featureLabel(display.program)
54758
- }),
54759
- display.remaining != null && /* @__PURE__ */ jsxs("span", {
54760
- className: "inline-flex items-center gap-1 text-sm text-foreground-subtle tabular-nums",
54761
- children: [/* @__PURE__ */ jsx(Timer, { className: "h-3.5 w-3.5" }), t("uiLibrary.dishwasher.remaining", "{{time}} left", { time: formatDuration(display.remaining, t) })]
54762
- }),
54763
- display.delayedStart != null && display.delayedStart > 0 && /* @__PURE__ */ jsx("span", {
54764
- className: "text-xs text-foreground-subtle tabular-nums",
54765
- children: t("uiLibrary.dishwasher.startsIn", "Starts in {{time}}", { time: formatDuration(display.delayedStart, t) })
54766
- }),
54767
- display.progress != null && /* @__PURE__ */ jsxs("div", {
54768
- className: "flex items-center gap-2",
54769
- children: [/* @__PURE__ */ jsx("div", {
54770
- className: "h-1.5 flex-1 rounded bg-surface-hover overflow-hidden",
54771
- children: /* @__PURE__ */ jsx("div", {
54772
- className: "h-full bg-primary transition-[width] duration-500",
54773
- style: { width: `${Math.max(0, Math.min(100, display.progress))}%` }
54774
- })
54775
- }), /* @__PURE__ */ jsxs("span", {
54776
- className: "tabular-nums text-xs text-foreground-subtle",
54777
- children: [Math.round(display.progress), "%"]
54778
- })]
54779
- }),
54780
- /* @__PURE__ */ jsxs("div", {
54781
- className: "flex flex-wrap items-center gap-x-3 gap-y-1.5",
54782
- children: [display.doorOpen === true && /* @__PURE__ */ jsxs("span", {
54783
- className: "inline-flex items-center gap-1 text-xs text-warning",
54784
- children: [/* @__PURE__ */ jsx(DoorOpen, { className: "h-3.5 w-3.5" }), t("uiLibrary.dishwasher.doorOpen", "Door open")]
54785
- }), visibleDishwasherEvents(display.activeEvents).map((event) => /* @__PURE__ */ jsx("span", {
54786
- className: "text-xs text-warning",
54787
- title: event,
54788
- children: featureLabel(event)
54789
- }, event))]
54790
- }),
54791
- display.operationState === "Error" && /* @__PURE__ */ jsxs("div", {
54792
- className: "inline-flex items-center gap-1 text-xs text-danger",
54793
- children: [/* @__PURE__ */ jsx(TriangleAlert, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ jsx("span", { children: display.errorLabel != null ? featureLabel(display.errorLabel) : display.errorCode != null ? t("uiLibrary.dishwasher.errorCode", "Error {{code}}", { code: display.errorCode }) : t("uiLibrary.dishwasher.op.error", "Error") })]
54794
- }),
54795
- /* @__PURE__ */ jsxs("div", {
54796
- className: "flex flex-wrap items-center gap-2",
54797
- children: [
54798
- /* @__PURE__ */ jsx(DishwasherIconButton, {
54799
- label: t("uiLibrary.dishwasher.start", "Start"),
54800
- busy: busy || !startable,
54801
- active: running,
54802
- onClick: () => press(() => cap.start({})),
54803
- children: /* @__PURE__ */ jsx(Play, { className: "h-4 w-4" })
54804
- }),
54805
- /* @__PURE__ */ jsx(DishwasherIconButton, {
54806
- label: paused ? t("uiLibrary.dishwasher.resume", "Resume") : t("uiLibrary.dishwasher.pause", "Pause"),
54807
- busy: busy || !(running || paused),
54808
- active: paused,
54809
- onClick: () => press(() => paused ? cap.resume({}) : cap.pause({})),
54810
- children: /* @__PURE__ */ jsx(Pause, { className: "h-4 w-4" })
54811
- }),
54812
- /* @__PURE__ */ jsx(DishwasherIconButton, {
54813
- label: t("uiLibrary.dishwasher.stop", "Stop"),
54814
- busy: busy || !(running || paused),
54815
- active: false,
54816
- onClick: () => press(() => cap.stop({})),
54817
- children: /* @__PURE__ */ jsx(Square, { className: "h-3.5 w-3.5" })
54818
- }),
54819
- /* @__PURE__ */ jsx(DishwasherIconButton, {
54820
- label: t("uiLibrary.dishwasher.power", "Power"),
54821
- busy: busy || display.powerOn === null,
54822
- active: display.powerOn === true,
54823
- onClick: () => {
54824
- const next = display.powerOn !== true;
54825
- press(() => cap.setPower({ on: next }));
54826
- },
54827
- children: /* @__PURE__ */ jsx(Power, { className: "h-4 w-4" })
54828
- })
54829
- ]
54830
- })
54831
- ]
54832
- })]
54833
- }),
54834
- programs.length > 0 && /* @__PURE__ */ jsxs("label", {
54835
- className: "flex items-center gap-2 text-xs text-foreground-subtle",
54836
- children: [/* @__PURE__ */ jsx("span", {
54837
- className: "w-16 shrink-0",
54838
- children: t("uiLibrary.dishwasher.program", "Program")
54839
- }), /* @__PURE__ */ jsxs("select", {
54840
- "aria-label": t("uiLibrary.dishwasher.program", "Program"),
54841
- value: display.selectedProgram ?? "",
54842
- disabled: busy,
54843
- onChange: (e) => {
54844
- const program = e.target.value;
54845
- if (!program) return;
54846
- cap.setProgram({ program });
54847
- },
54848
- onClick: (e) => {
54849
- e.stopPropagation();
54850
- },
54851
- className: "flex-1 rounded border border-border bg-surface px-2 py-1 text-foreground disabled:opacity-50",
54852
- children: [display.selectedProgram == null && /* @__PURE__ */ jsx("option", {
54853
- value: "",
54854
- children: "—"
54855
- }), programs.map((p) => /* @__PURE__ */ jsx("option", {
54856
- value: p,
54857
- children: featureLabel(p)
54858
- }, p))]
54859
- })]
54860
- }),
54861
- /* @__PURE__ */ jsxs("div", {
54862
- className: "flex flex-wrap gap-4 text-xs",
54982
+ className: "relative z-10 flex flex-col items-center justify-center gap-1 overflow-hidden rounded-lg border border-border/50 bg-surface/30 px-3 py-3",
54863
54983
  children: [
54864
- /* @__PURE__ */ jsx(ToggleRow, {
54865
- label: t("uiLibrary.dishwasher.halfLoad", "Half load"),
54866
- checked: display.halfLoad,
54867
- shown: link,
54868
- busy: busy || optionTogglesLocked,
54869
- onChange: (on) => void cap.setHalfLoad({ on })
54984
+ /* @__PURE__ */ jsx("div", {
54985
+ className: "pointer-events-none absolute inset-0 opacity-60",
54986
+ children: heatingOnly && !on ? /* @__PURE__ */ jsx(RadiatorFins, {}) : /* @__PURE__ */ jsx(AirflowViz, {
54987
+ mode: display.mode,
54988
+ accent,
54989
+ periodSec: period,
54990
+ swaying,
54991
+ forceRising: heatingOnly
54992
+ })
54870
54993
  }),
54871
- /* @__PURE__ */ jsx(ToggleRow, {
54872
- label: t("uiLibrary.dishwasher.hygienePlus", "Hygiene plus"),
54873
- checked: display.hygienePlus,
54874
- shown: link,
54875
- busy: busy || optionTogglesLocked,
54876
- onChange: (on) => void cap.setHygienePlus({ on })
54994
+ /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 bg-gradient-to-b from-surface/50 via-transparent to-surface/50" }),
54995
+ on && /* @__PURE__ */ jsx("span", {
54996
+ "aria-hidden": true,
54997
+ className: "acv-glow pointer-events-none absolute left-1/2 top-1/2 h-16 w-16 -translate-x-1/2 -translate-y-1/2 rounded-full blur-2xl",
54998
+ style: {
54999
+ background: accent,
55000
+ animation: "acv-glow 3.2s ease-in-out infinite"
55001
+ }
54877
55002
  }),
54878
- /* @__PURE__ */ jsx(ToggleRow, {
54879
- label: t("uiLibrary.dishwasher.extraDry", "Extra dry"),
54880
- checked: display.extraDry,
54881
- shown: link,
54882
- busy: busy || optionTogglesLocked,
54883
- onChange: (on) => void cap.setExtraDry({ on })
55003
+ /* @__PURE__ */ jsxs("div", {
55004
+ className: "relative z-10 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide",
55005
+ style: { color: accent },
55006
+ children: [
55007
+ /* @__PURE__ */ jsx(ModeIcon, {
55008
+ mode: display.mode,
55009
+ heatingOnly,
55010
+ className: "h-3.5 w-3.5"
55011
+ }),
55012
+ modeLabel(t, display.mode),
55013
+ display.currentTemp !== null && /* @__PURE__ */ jsx("span", {
55014
+ className: "normal-case text-foreground-subtle",
55015
+ children: t("uiLibrary.acPanel.now", "· {{temp}}° now", { temp: display.currentTemp })
55016
+ }),
55017
+ display.currentHumidity !== null && /* @__PURE__ */ jsxs("span", {
55018
+ className: "inline-flex items-center gap-0.5 normal-case text-foreground-subtle",
55019
+ children: [
55020
+ /* @__PURE__ */ jsx(Droplets, { className: "h-3 w-3" }),
55021
+ display.currentHumidity,
55022
+ "%"
55023
+ ]
55024
+ })
55025
+ ]
54884
55026
  }),
54885
- /* @__PURE__ */ jsx(ToggleRow, {
54886
- label: t("uiLibrary.dishwasher.intensiveZone", "Intensive zone"),
54887
- checked: display.intensiveZone,
54888
- shown: link,
54889
- busy: busy || optionTogglesLocked,
54890
- onChange: (on) => void cap.setIntensiveZone({ on })
55027
+ display.target !== null ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
55028
+ className: "relative z-10 flex items-center gap-3",
55029
+ children: [
55030
+ /* @__PURE__ */ jsx(RoundStep, {
55031
+ label: t("uiLibrary.acPanel.decrease", "Decrease target"),
55032
+ symbol: "−",
55033
+ disabled: busy,
55034
+ onClick: () => {
55035
+ if (busy || display.target === null) return;
55036
+ const next = nextClimateTarget(display.target, -1, display);
55037
+ applyOptimistic({ target: next });
55038
+ cap.setTarget({ target: next });
55039
+ }
55040
+ }),
55041
+ /* @__PURE__ */ jsxs("div", {
55042
+ className: "flex items-baseline gap-0.5",
55043
+ children: [/* @__PURE__ */ jsx("span", {
55044
+ className: cn("text-4xl font-bold leading-none tabular-nums", climateTargetWidthClass(display)),
55045
+ style: { color: accent },
55046
+ children: display.target
55047
+ }), /* @__PURE__ */ jsx("span", {
55048
+ className: "text-lg text-foreground-subtle",
55049
+ children: "°"
55050
+ })]
55051
+ }),
55052
+ /* @__PURE__ */ jsx(RoundStep, {
55053
+ label: t("uiLibrary.acPanel.increase", "Increase target"),
55054
+ symbol: "+",
55055
+ disabled: busy,
55056
+ onClick: () => {
55057
+ if (busy || display.target === null) return;
55058
+ const next = nextClimateTarget(display.target, 1, display);
55059
+ applyOptimistic({ target: next });
55060
+ cap.setTarget({ target: next });
55061
+ }
55062
+ })
55063
+ ]
55064
+ }), setpointBounds !== null && /* @__PURE__ */ jsx("div", {
55065
+ className: "relative z-10 w-full px-1",
55066
+ children: /* @__PURE__ */ jsx(RangeTrack, {
55067
+ value: display.target,
55068
+ min: setpointBounds.min,
55069
+ max: setpointBounds.max,
55070
+ step: display.tempStep,
55071
+ accent,
55072
+ disabled: busy,
55073
+ label: t("uiLibrary.acPanel.setpoint", "Setpoint"),
55074
+ onPreview: (next) => {
55075
+ applyOptimistic({ target: next });
55076
+ },
55077
+ onCommit: (next) => {
55078
+ applyOptimistic({ target: next });
55079
+ cap.setTarget({ target: next });
55080
+ }
55081
+ })
55082
+ })] }) : /* @__PURE__ */ jsxs("div", {
55083
+ className: "relative z-10 flex items-baseline gap-0.5",
55084
+ children: [/* @__PURE__ */ jsx("span", {
55085
+ className: cn("text-4xl font-bold leading-none tabular-nums text-foreground", climateTargetWidthClass(display)),
55086
+ children: display.currentTemp ?? "—"
55087
+ }), /* @__PURE__ */ jsx("span", {
55088
+ className: "text-lg text-foreground-subtle",
55089
+ children: "°"
55090
+ })]
55091
+ })
55092
+ ]
55093
+ }),
55094
+ /* @__PURE__ */ jsxs("div", {
55095
+ className: "relative z-10 grid grid-cols-3 gap-2",
55096
+ children: [
55097
+ /* @__PURE__ */ jsx(CompactSelect, {
55098
+ label: t("uiLibrary.acPanel.mode", "Mode"),
55099
+ icon: /* @__PURE__ */ jsx("span", {
55100
+ style: { color: accent },
55101
+ className: "flex",
55102
+ children: /* @__PURE__ */ jsx(ModeIcon, {
55103
+ mode: display.mode,
55104
+ heatingOnly,
55105
+ className: "h-4 w-4"
55106
+ })
55107
+ }),
55108
+ value: display.mode,
55109
+ options: display.availableModes.map((m) => ({
55110
+ value: m,
55111
+ label: modeLabel(t, m)
55112
+ })),
55113
+ disabled: busy,
55114
+ onChange: (v) => {
55115
+ const mode = display.availableModes.find((m) => m === v);
55116
+ if (mode) {
55117
+ applyOptimistic({ mode });
55118
+ cap.setMode({ mode });
55119
+ }
55120
+ }
54891
55121
  }),
54892
- /* @__PURE__ */ jsx(ToggleRow, {
54893
- label: t("uiLibrary.dishwasher.varioSpeedPlus", "VarioSpeed+"),
54894
- checked: display.varioSpeedPlus,
54895
- shown: link,
54896
- busy: busy || optionTogglesLocked,
54897
- onChange: (on) => void cap.setVarioSpeedPlus({ on })
55122
+ display.availableFanModes.length > 0 && /* @__PURE__ */ jsx(CompactSelect, {
55123
+ label: t("uiLibrary.acPanel.fan", "Fan"),
55124
+ icon: /* @__PURE__ */ jsx(Wind, { className: "h-4 w-4 text-sky-500" }),
55125
+ value: display.fanMode,
55126
+ options: display.availableFanModes.map((f) => ({
55127
+ value: f,
55128
+ label: fanLabel(f)
55129
+ })),
55130
+ disabled: busy,
55131
+ onChange: (v) => {
55132
+ applyOptimistic({ fanMode: v });
55133
+ cap.setFanMode({ fanMode: v });
55134
+ }
54898
55135
  }),
54899
- /* @__PURE__ */ jsx(ToggleRow, {
54900
- label: t("uiLibrary.dishwasher.childLock", "Child lock"),
54901
- checked: display.childLock,
54902
- shown: link,
54903
- busy,
54904
- onChange: (on) => void cap.setChildLock({ on })
55136
+ display.availablePresets.length > 0 && /* @__PURE__ */ jsx(CompactSelect, {
55137
+ label: t("uiLibrary.acPanel.preset", "Preset"),
55138
+ icon: /* @__PURE__ */ jsx(CurrentPresetIcon, { className: "h-4 w-4 text-emerald-500" }),
55139
+ value: display.preset,
55140
+ options: display.availablePresets.map((p) => ({
55141
+ value: p,
55142
+ label: fanLabel(p)
55143
+ })),
55144
+ disabled: busy,
55145
+ onChange: (v) => {
55146
+ applyOptimistic({ preset: v });
55147
+ cap.setPreset({ preset: v });
55148
+ }
54905
55149
  })
54906
55150
  ]
54907
- })
54908
- ]
54909
- });
54910
- }
54911
- /**
54912
- * One boolean setting. `checked === null` is "the appliance has not said": on a reachable
54913
- * appliance that means it does not offer the setting (hidden); on an unreachable one the
54914
- * setting is shown but disabled and marked unknown — never as an unchecked box.
54915
- */
54916
- function ToggleRow({ label, checked, shown, busy, onChange }) {
54917
- const t = useUiText();
54918
- if (checked === null && shown) return null;
54919
- return /* @__PURE__ */ jsxs("label", {
54920
- className: "inline-flex items-center gap-2 cursor-pointer",
54921
- children: [
54922
- /* @__PURE__ */ jsx("input", {
54923
- type: "checkbox",
54924
- checked: checked === true,
54925
- "aria-checked": checked === null ? "mixed" : checked,
54926
- disabled: busy || checked === null,
54927
- onChange: (e) => {
54928
- onChange(e.target.checked);
54929
- },
54930
- onClick: (e) => {
54931
- e.stopPropagation();
54932
- },
54933
- className: "rounded border-border"
54934
55151
  }),
54935
- /* @__PURE__ */ jsx("span", { children: label }),
54936
- checked === null && /* @__PURE__ */ jsx("span", {
54937
- className: "text-foreground-subtle",
54938
- children: t("uiLibrary.dishwasher.unknownValue", "—")
55152
+ (showVSwing || showHSwing) && /* @__PURE__ */ jsx(Field, {
55153
+ label: t("uiLibrary.acPanel.swing", "Swing"),
55154
+ children: /* @__PURE__ */ jsxs("div", {
55155
+ className: "grid grid-cols-2 gap-1",
55156
+ children: [showVSwing && /* @__PURE__ */ jsx(SwingToggle, {
55157
+ axis: "vertical",
55158
+ on: display.swingVertical ?? false,
55159
+ busy,
55160
+ onToggle: (next) => {
55161
+ applyOptimistic({ swingVertical: next });
55162
+ cap.setSwingVertical({ on: next });
55163
+ }
55164
+ }), showHSwing && /* @__PURE__ */ jsx(SwingToggle, {
55165
+ axis: "horizontal",
55166
+ on: display.swingHorizontal ?? false,
55167
+ busy,
55168
+ onToggle: (next) => {
55169
+ applyOptimistic({ swingHorizontal: next });
55170
+ cap.setSwingHorizontal({ on: next });
55171
+ }
55172
+ })]
55173
+ })
54939
55174
  })
54940
55175
  ]
54941
55176
  });
54942
55177
  }
54943
- function DishwasherInlineControl(props) {
54944
- return /* @__PURE__ */ jsx(DishwasherPanel, {
54945
- ...props,
54946
- layout: "compact"
55178
+ /** Labelled control group — a small uppercase header above its control. */
55179
+ function Field({ label, children }) {
55180
+ return /* @__PURE__ */ jsxs("div", {
55181
+ className: "relative z-10 flex flex-col gap-1",
55182
+ children: [/* @__PURE__ */ jsx("span", {
55183
+ className: "text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle",
55184
+ children: label
55185
+ }), children]
54947
55186
  });
54948
55187
  }
54949
- function DishwasherHeroCard(props) {
54950
- return /* @__PURE__ */ jsx(DishwasherPanel, {
54951
- ...props,
54952
- layout: "full"
55188
+ function ModeIcon({ mode, heatingOnly = false, className }) {
55189
+ return /* @__PURE__ */ jsx(heatingOnly && mode === "heat" ? Heater : MODE_ICON[mode], {
55190
+ className,
55191
+ "aria-hidden": true
54953
55192
  });
54954
55193
  }
54955
- //#endregion
54956
- //#region src/composites/device-controls/appliance-control.tsx
54957
- /**
54958
- * Appliance card for a `DeviceType.Washer` / `DeviceType.Dryer` device.
54959
- *
54960
- * These appliances have no program surface: what is worth showing is whether
54961
- * the cycle is running (the `running-state` cap), for how long, and what the
54962
- * appliance draws right now (the `power-meter` cap). Both slices are read
54963
- * straight from the device; neither is required.
54964
- * - ApplianceInlineControl (device-list row): the running badge round the
54965
- * drum icon, plus the live watts when there are any.
54966
- * - ApplianceHeroCard (device-detail hero): the drum (turning only while a
54967
- * cycle runs), the state, the phase, the dwell and the power.
54968
- *
54969
- * UNKNOWN IS NOT OFF (D393). `running: null` is drawn as "Unknown" and the
54970
- * drum stays still and unbadged; a missing watt reading is a dash, never
54971
- * "0 W". A slice that has not landed hides its row instead of faking a value.
54972
- */
54973
- var KEYFRAMES$1 = `
54974
- @keyframes apl-tumble { to { transform: rotate(360deg) } }
54975
- .apl-drum-run { animation: apl-tumble 3s linear infinite; }
54976
- @media (prefers-reduced-motion: reduce) {
54977
- .apl-drum-run { animation: none !important; }
55194
+ /** Compact labelled dropdown — a leading icon + native `<select>` + chevron,
55195
+ * used for the Mode / Fan / Preset selectors so all three fit in one row. */
55196
+ function CompactSelect({ label, icon, value, options, disabled, onChange }) {
55197
+ return /* @__PURE__ */ jsxs("div", {
55198
+ className: "flex min-w-0 flex-col gap-1",
55199
+ children: [/* @__PURE__ */ jsx("span", {
55200
+ className: "text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle",
55201
+ children: label
55202
+ }), /* @__PURE__ */ jsxs("div", {
55203
+ className: cn("flex items-center gap-1 overflow-hidden rounded-lg border border-border/60 bg-surface-subtle px-1.5 py-1.5 has-[:focus-visible]:border-primary", disabled && "opacity-40"),
55204
+ children: [
55205
+ /* @__PURE__ */ jsx("span", {
55206
+ className: "flex shrink-0",
55207
+ children: icon
55208
+ }),
55209
+ /* @__PURE__ */ jsx("select", {
55210
+ "aria-label": label,
55211
+ value,
55212
+ disabled,
55213
+ onChange: (e) => {
55214
+ e.stopPropagation();
55215
+ if (!disabled) onChange(e.target.value);
55216
+ },
55217
+ className: "min-w-0 flex-1 cursor-pointer appearance-none truncate bg-transparent text-xs font-medium text-foreground outline-none",
55218
+ children: options.map((o) => /* @__PURE__ */ jsx("option", {
55219
+ value: o.value,
55220
+ children: o.label
55221
+ }, o.value))
55222
+ }),
55223
+ /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3 shrink-0 text-foreground-subtle" })
55224
+ ]
55225
+ })]
55226
+ });
54978
55227
  }
54979
- `;
54980
- /** Whole watts, or a dash when the appliance has not reported a reading. */
54981
- function formatWatts(power) {
54982
- return power === void 0 || !Number.isFinite(power) ? "—" : `${Math.round(power)} W`;
55228
+ /** Circular ± button for the target. */
55229
+ function RoundStep({ label, symbol, disabled, onClick }) {
55230
+ return /* @__PURE__ */ jsx("button", {
55231
+ type: "button",
55232
+ "aria-label": label,
55233
+ disabled,
55234
+ onClick,
55235
+ className: cn("flex h-8 w-8 shrink-0 items-center justify-center rounded-full border border-border bg-surface text-lg leading-none text-foreground-subtle transition-colors hover:bg-surface-hover hover:text-foreground active:scale-95", disabled && "opacity-40 cursor-not-allowed"),
55236
+ children: symbol
55237
+ });
54983
55238
  }
54984
- /** The state to a person: running / idle, or why there is none (unknown). */
54985
- function applianceStateLabel(running, t) {
54986
- if (running === true) return {
54987
- label: t("uiLibrary.appliance.running", "Running"),
54988
- tone: "text-primary"
55239
+ /** Setpoint track. Drag previews; the command is sent when the pointer is released. */
55240
+ function RangeTrack({ value, min, max, step, accent, disabled, label, onPreview, onCommit }) {
55241
+ const trackRef = useRef(null);
55242
+ const draggingRef = useRef(false);
55243
+ const [draft, setDraft] = useState(null);
55244
+ const shown = draft ?? value;
55245
+ const pct = `${Math.min(1, Math.max(0, (shown - min) / (max - min))) * 100}%`;
55246
+ const tempAt = (clientX) => {
55247
+ const el = trackRef.current;
55248
+ if (el === null) return value;
55249
+ const rect = el.getBoundingClientRect();
55250
+ if (rect.width <= 0) return value;
55251
+ return climateTargetFromFraction((clientX - rect.left) / rect.width, {
55252
+ min,
55253
+ max
55254
+ }, step);
54989
55255
  };
54990
- if (running === false) return {
54991
- label: t("uiLibrary.appliance.idle", "Idle"),
54992
- tone: "text-foreground"
55256
+ const onPointerDown = (event) => {
55257
+ if (disabled) return;
55258
+ event.stopPropagation();
55259
+ event.preventDefault();
55260
+ draggingRef.current = true;
55261
+ if (typeof event.currentTarget.setPointerCapture === "function") event.currentTarget.setPointerCapture(event.pointerId);
55262
+ const next = tempAt(event.clientX);
55263
+ setDraft(next);
55264
+ onPreview(next);
54993
55265
  };
54994
- return {
54995
- label: t("uiLibrary.appliance.unknown", "Unknown"),
54996
- tone: "text-foreground-subtle"
55266
+ const onPointerMove = (event) => {
55267
+ if (disabled || !draggingRef.current) return;
55268
+ event.stopPropagation();
55269
+ const next = tempAt(event.clientX);
55270
+ setDraft(next);
55271
+ onPreview(next);
54997
55272
  };
54998
- }
54999
- function dwellText(running, since, now, t) {
55000
- if (running !== true) return null;
55001
- const { duration } = runningStatusParts(running, since, null, now);
55002
- if (duration === void 0) return null;
55003
- return "minutes" in duration ? t("uiLibrary.appliance.forMinutes", "for {{count}} min", { count: duration.minutes }) : t("uiLibrary.appliance.forHours", "for {{count}} h", { count: duration.hours });
55004
- }
55005
- function useApplianceState(props) {
55006
- return {
55007
- running: useDeviceState(props.trpc, props.deviceId, (s) => s.runningState),
55008
- power: useDeviceState(props.trpc, props.deviceId, (s) => s.powerMeter)
55273
+ const endDrag = (event) => {
55274
+ if (!draggingRef.current) return;
55275
+ event.stopPropagation();
55276
+ draggingRef.current = false;
55277
+ const next = tempAt(event.clientX);
55278
+ setDraft(null);
55279
+ if (event.currentTarget.hasPointerCapture?.(event.pointerId) === true) event.currentTarget.releasePointerCapture(event.pointerId);
55280
+ onCommit(next);
55009
55281
  };
55282
+ const onKeyDown = (event) => {
55283
+ if (disabled) return;
55284
+ const current = draft ?? value;
55285
+ if (event.key === "ArrowRight" || event.key === "ArrowUp") {
55286
+ event.preventDefault();
55287
+ onCommit(nextClimateTarget(current, 1, {
55288
+ tempStep: step,
55289
+ minTemp: min,
55290
+ maxTemp: max
55291
+ }));
55292
+ } else if (event.key === "ArrowLeft" || event.key === "ArrowDown") {
55293
+ event.preventDefault();
55294
+ onCommit(nextClimateTarget(current, -1, {
55295
+ tempStep: step,
55296
+ minTemp: min,
55297
+ maxTemp: max
55298
+ }));
55299
+ } else if (event.key === "Home") {
55300
+ event.preventDefault();
55301
+ onCommit(min);
55302
+ } else if (event.key === "End") {
55303
+ event.preventDefault();
55304
+ onCommit(max);
55305
+ }
55306
+ };
55307
+ return /* @__PURE__ */ jsxs("div", {
55308
+ ref: trackRef,
55309
+ role: "slider",
55310
+ "aria-label": label,
55311
+ "aria-valuemin": min,
55312
+ "aria-valuemax": max,
55313
+ "aria-valuenow": shown,
55314
+ "aria-disabled": disabled,
55315
+ tabIndex: disabled ? -1 : 0,
55316
+ onPointerDown,
55317
+ onPointerMove,
55318
+ onPointerUp: endDrag,
55319
+ onPointerCancel: endDrag,
55320
+ onKeyDown,
55321
+ className: cn("mt-1 w-full touch-none select-none py-2", disabled ? "cursor-not-allowed opacity-40" : "cursor-ew-resize"),
55322
+ children: [/* @__PURE__ */ jsxs("div", {
55323
+ className: "relative h-1.5 w-full rounded-full bg-surface-subtle",
55324
+ children: [/* @__PURE__ */ jsx("div", {
55325
+ className: "absolute inset-y-0 left-0 rounded-full",
55326
+ style: {
55327
+ width: pct,
55328
+ background: accent
55329
+ }
55330
+ }), /* @__PURE__ */ jsx("div", {
55331
+ className: "absolute top-1/2 h-3.5 w-3.5 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-surface shadow",
55332
+ style: {
55333
+ left: pct,
55334
+ background: accent
55335
+ }
55336
+ })]
55337
+ }), /* @__PURE__ */ jsxs("div", {
55338
+ className: "mt-0.5 flex justify-between text-[9px] tabular-nums text-foreground-subtle",
55339
+ children: [/* @__PURE__ */ jsxs("span", { children: [min, "°"] }), /* @__PURE__ */ jsxs("span", { children: [max, "°"] })]
55340
+ })]
55341
+ });
55010
55342
  }
55011
- /** The drum: a ring with a few items in it, turning only while a cycle runs. */
55012
- function Drum({ running }) {
55343
+ /**
55344
+ * Animated centerpiece. `fan_only` renders a spinning fan; `off` a dim static
55345
+ * vent; every active mode renders drifting particles that FALL (cool/dry/auto)
55346
+ * or RISE (heat), with a horizontal sweep overlaid when a swing axis is active.
55347
+ */
55348
+ function AirflowViz({ mode, accent, periodSec, swaying, forceRising = false }) {
55349
+ const columns = [
55350
+ 0,
55351
+ 1,
55352
+ 2,
55353
+ 3,
55354
+ 4,
55355
+ 5
55356
+ ];
55357
+ const rising = forceRising || mode === "heat";
55358
+ const isDroplet = mode === "dry";
55013
55359
  return /* @__PURE__ */ jsx("div", {
55014
- "aria-hidden": "true",
55015
- "data-testid": "appliance-drum",
55016
- "data-running": running === true ? "running" : running === false ? "idle" : "unknown",
55017
- className: "relative flex h-28 w-28 shrink-0 items-center justify-center rounded-full border-2 border-border bg-surface-hover",
55018
- children: /* @__PURE__ */ jsxs("div", {
55019
- className: cn("relative h-20 w-20 rounded-full border-2", running === true ? "apl-drum-run border-primary" : "border-border"),
55020
- "data-testid": "appliance-drum-ring",
55021
- children: [
55022
- /* @__PURE__ */ jsx("span", { className: "absolute left-2 top-4 h-3 w-3 rounded-full bg-primary/40" }),
55023
- /* @__PURE__ */ jsx("span", { className: "absolute bottom-3 right-3 h-4 w-4 rounded-full bg-info/40" }),
55024
- /* @__PURE__ */ jsx("span", { className: "absolute bottom-4 left-4 h-2.5 w-2.5 rounded-full bg-foreground-subtle/40" })
55025
- ]
55360
+ "aria-hidden": true,
55361
+ className: "absolute inset-0 overflow-hidden",
55362
+ children: mode === "off" ? /* @__PURE__ */ jsx("div", {
55363
+ className: "flex h-full items-center justify-center gap-2 opacity-30",
55364
+ children: columns.map((i) => /* @__PURE__ */ jsx("span", { className: "h-8 w-1 rounded-full bg-foreground-subtle opacity-40" }, i))
55365
+ }) : mode === "fan_only" ? /* @__PURE__ */ jsx("div", {
55366
+ className: "flex h-full items-center justify-center",
55367
+ children: /* @__PURE__ */ jsx(FanBlades, {
55368
+ color: accent,
55369
+ periodSec: Math.max(.5, periodSec * .7),
55370
+ size: 56
55371
+ })
55372
+ }) : /* @__PURE__ */ jsx("div", {
55373
+ "data-testid": forceRising ? "climate-heat-rise" : void 0,
55374
+ className: cn("acv-sway-wrap absolute inset-0", swaying && "acv-sway"),
55375
+ style: swaying ? { animation: "acv-sway 2.6s ease-in-out infinite" } : void 0,
55376
+ children: columns.map((i) => {
55377
+ return /* @__PURE__ */ jsx("span", {
55378
+ className: "acv-streak absolute rounded-full",
55379
+ style: {
55380
+ left: `${8 + i * 15}%`,
55381
+ width: isDroplet ? "0.4rem" : "0.3rem",
55382
+ height: isDroplet ? "0.4rem" : "1.9rem",
55383
+ background: accent,
55384
+ boxShadow: `0 0 6px ${accent}`,
55385
+ animationName: rising ? "acv-rise" : "acv-fall",
55386
+ animationTimingFunction: "linear",
55387
+ animationIterationCount: "infinite",
55388
+ animationDuration: `${periodSec}s`,
55389
+ animationDelay: `${i % 3 * (periodSec / 3) + i * .05}s`
55390
+ }
55391
+ }, i);
55392
+ })
55026
55393
  })
55027
55394
  });
55028
55395
  }
55029
- function ApplianceHeroCard(props) {
55030
- const t = useUiText();
55031
- const { running, power } = useApplianceState(props);
55032
- const state = running?.running ?? null;
55033
- const meta = applianceStateLabel(state, t);
55034
- const phase = running?.phase?.trim() ?? "";
55035
- const dwell = running === void 0 ? null : dwellText(state, running.since, Date.now(), t);
55036
- return /* @__PURE__ */ jsxs("div", {
55037
- className: "flex items-center gap-4 rounded-lg border border-border bg-surface p-4",
55396
+ /** Still radiator fins — the off state of a heating-only climate. */
55397
+ function RadiatorFins() {
55398
+ return /* @__PURE__ */ jsx("div", {
55399
+ "data-testid": "climate-radiator",
55400
+ "aria-hidden": true,
55401
+ className: "flex h-full items-end justify-center gap-1.5 px-8 pb-3 opacity-40",
55038
55402
  children: [
55039
- /* @__PURE__ */ jsx("style", { children: KEYFRAMES$1 }),
55040
- /* @__PURE__ */ jsx(Drum, { running: state }),
55041
- /* @__PURE__ */ jsxs("div", {
55042
- className: "flex min-w-0 flex-1 flex-col gap-2",
55043
- children: [
55044
- /* @__PURE__ */ jsxs("div", {
55045
- className: "flex flex-wrap items-baseline gap-x-2",
55046
- children: [/* @__PURE__ */ jsx("span", {
55047
- "data-testid": "appliance-state",
55048
- className: cn("text-3xl font-semibold", meta.tone),
55049
- children: meta.label
55050
- }), dwell !== null && /* @__PURE__ */ jsx("span", {
55051
- className: "text-sm tabular-nums text-foreground-subtle",
55052
- children: dwell
55053
- })]
55054
- }),
55055
- phase !== "" && state !== null && /* @__PURE__ */ jsx("span", {
55056
- className: "text-sm text-foreground-subtle",
55057
- children: phase
55058
- }),
55059
- power !== void 0 && /* @__PURE__ */ jsxs("span", {
55060
- "data-testid": "appliance-power",
55061
- className: "inline-flex items-center gap-1 text-sm tabular-nums text-foreground-muted",
55062
- title: power.power === void 0 ? t("uiLibrary.appliance.powerUnknown", "Power unknown") : void 0,
55063
- children: [/* @__PURE__ */ jsx(Zap, {
55064
- className: "h-3.5 w-3.5",
55065
- "aria-hidden": true
55066
- }), formatWatts(power.power)]
55067
- })
55068
- ]
55069
- })
55070
- ]
55403
+ 0,
55404
+ 1,
55405
+ 2,
55406
+ 3,
55407
+ 4,
55408
+ 5,
55409
+ 6
55410
+ ].map((i) => /* @__PURE__ */ jsx("span", { className: "h-10 w-1.5 rounded-t-full bg-foreground-subtle" }, i))
55071
55411
  });
55072
55412
  }
55073
- function ApplianceInlineControl(props) {
55074
- const { running, power } = useApplianceState(props);
55075
- return /* @__PURE__ */ jsxs("div", {
55076
- className: "inline-flex items-center gap-1.5 max-w-full",
55077
- children: [/* @__PURE__ */ jsx(RunningBadge, {
55078
- running: running?.running ?? null,
55079
- children: /* @__PURE__ */ jsx(WashingMachine, {
55080
- className: "h-4 w-4 text-foreground-muted",
55081
- "aria-hidden": true
55082
- })
55083
- }), power !== void 0 && /* @__PURE__ */ jsx("span", {
55084
- className: "text-xs tabular-nums text-foreground-subtle",
55085
- children: formatWatts(power.power)
55413
+ /** Big spinning fan for `fan_only` mode. */
55414
+ function FanBlades({ color, periodSec, size }) {
55415
+ return /* @__PURE__ */ jsxs("svg", {
55416
+ width: size,
55417
+ height: size,
55418
+ viewBox: "0 0 100 100",
55419
+ className: "acv-fan",
55420
+ style: {
55421
+ animation: `acv-spin ${periodSec}s linear infinite`,
55422
+ transformOrigin: "50% 50%"
55423
+ },
55424
+ "aria-hidden": true,
55425
+ children: [[
55426
+ 0,
55427
+ 120,
55428
+ 240
55429
+ ].map((deg) => /* @__PURE__ */ jsx("path", {
55430
+ d: "M50 50 C 58 30, 78 26, 84 12 C 66 20, 54 34, 50 50 Z",
55431
+ fill: color,
55432
+ opacity: .85,
55433
+ transform: `rotate(${deg} 50 50)`
55434
+ }, deg)), /* @__PURE__ */ jsx("circle", {
55435
+ cx: "50",
55436
+ cy: "50",
55437
+ r: "7",
55438
+ fill: color
55086
55439
  })]
55087
55440
  });
55088
55441
  }
55089
- //#endregion
55090
- //#region src/composites/device-controls/heating-valve-readout.tsx
55091
- function formatHeatingValvePosition(position) {
55092
- return position !== null ? `${position}%` : "—";
55093
- }
55094
- function HeatingValveReadout({ trpc, deviceId, layout }) {
55442
+ /** Swing axis toggle — a card with a MoveVertical/Horizontal glyph that
55443
+ * oscillates along its axis when on. On/off is non-destructive → plain tap. */
55444
+ function SwingToggle({ axis, on, busy, onToggle }) {
55095
55445
  const t = useUiText();
55096
- const { cap, slice } = useDeviceCapability({
55446
+ const label = axis === "vertical" ? t("uiLibrary.acPanel.vertical", "Vertical") : t("uiLibrary.acPanel.horizontal", "Horizontal");
55447
+ const Icon = axis === "vertical" ? MoveVertical : MoveHorizontal;
55448
+ const anim = axis === "vertical" ? "acv-swing-v" : "acv-swing-h";
55449
+ return /* @__PURE__ */ jsxs("button", {
55450
+ type: "button",
55451
+ "aria-label": t("uiLibrary.acPanel.swingAxis", "{{axis}} swing", { axis: label }),
55452
+ "aria-pressed": on,
55453
+ disabled: busy,
55454
+ onClick: () => {
55455
+ if (!busy) onToggle(!on);
55456
+ },
55457
+ className: cn("flex items-center justify-center gap-2 rounded-lg border px-2 py-1.5 text-xs font-medium transition-colors", on ? "border-transparent bg-indigo-400 text-indigo-950 shadow-sm" : "border-border/60 bg-surface-subtle text-foreground-subtle hover:bg-surface-hover hover:text-foreground", busy && "opacity-40 cursor-not-allowed"),
55458
+ children: [/* @__PURE__ */ jsx(Icon, {
55459
+ className: "acv-swing h-4 w-4",
55460
+ "aria-hidden": true,
55461
+ style: on ? { animation: `${anim} 1.4s ease-in-out infinite` } : void 0
55462
+ }), label]
55463
+ });
55464
+ }
55465
+ //#endregion
55466
+ //#region src/composites/device-controls/heater-control.tsx
55467
+ /**
55468
+ * Heater controls for a `DeviceType.Heater` device (a dumb plug-in stove).
55469
+ *
55470
+ * A heater is a switch that heats while it is on, and the hub can switch it off
55471
+ * again after a chosen time (`timed-run`, D993):
55472
+ * - HeaterInlineControl (device-list row): the on/off switch and a one-tap
55473
+ * "Run N min".
55474
+ * - HeaterHeroCard (device-detail hero): the glowing heat backdrop (the same
55475
+ * rising streaks a heating air conditioner draws) while it is on, the
55476
+ * on/off switch, the power draw when the plug measures one, and the timed
55477
+ * run (number, unit, Run, countdown, Cancel).
55478
+ *
55479
+ * Every reading may be unknown (`null`) and is drawn as a dash, never as zero.
55480
+ */
55481
+ var HEATER_LIMIT = TIMED_RUN_LIMITS[DeviceType.Heater];
55482
+ var QUICK_RUN_MINUTES = 30;
55483
+ var HEAT_ACCENT = "var(--color-warning)";
55484
+ var HEAT_PERIOD_SEC = 1.8;
55485
+ function useHeater({ trpc, deviceId, optimistic }) {
55486
+ const { cap, slice, available } = useDeviceCapability({
55097
55487
  trpc,
55098
55488
  deviceId,
55099
- cap: (d) => d.heatingValve,
55100
- slice: (d) => d.state.heatingValve
55489
+ cap: (d) => d.switch,
55490
+ slice: (d) => d.state.switch
55101
55491
  });
55102
- if (cap === void 0 || slice === void 0) return null;
55103
- const label = t("uiLibrary.heatingValveReadout.valve", "Valve");
55104
- const value = formatHeatingValvePosition(slice.position);
55105
- if (layout === "compact") return /* @__PURE__ */ jsx("span", {
55106
- className: "inline-flex items-center text-xs tabular-nums text-foreground-subtle",
55107
- "aria-label": `${label} ${value}`,
55108
- children: value
55492
+ const running = useDeviceCapability({
55493
+ trpc,
55494
+ deviceId,
55495
+ cap: (d) => d.runningState,
55496
+ slice: (d) => d.state.runningState
55109
55497
  });
55110
- return /* @__PURE__ */ jsxs("div", {
55111
- className: "flex items-center gap-2 text-xs tabular-nums text-foreground-subtle",
55112
- children: [/* @__PURE__ */ jsx("span", { children: label }), /* @__PURE__ */ jsx("span", {
55113
- className: "font-medium text-foreground",
55114
- children: value
55115
- })]
55498
+ const power = useDeviceCapability({
55499
+ trpc,
55500
+ deviceId,
55501
+ cap: (d) => d.powerMeter,
55502
+ slice: (d) => d.state.powerMeter
55116
55503
  });
55117
- }
55118
- //#endregion
55119
- //#region src/composites/device-controls/ac-panel.tsx
55120
- /** Modes that mean the device can cool, dry, or move air — an air conditioner. */
55121
- var COOLING_MODES = new Set([
55122
- "cool",
55123
- "heat_cool",
55124
- "dry",
55125
- "fan_only"
55126
- ]);
55127
- /** A heater offers heat (and maybe auto/off) and none of the cooling modes. */
55128
- function climateOffersCooling(modes) {
55129
- return modes.some((mode) => COOLING_MODES.has(mode));
55130
- }
55131
- /** Setpoint track bounds. Absent when the integration did not report both ends. */
55132
- function climateSetpointBounds(status) {
55133
- const min = status.minTemp;
55134
- const max = status.maxTemp;
55135
- if (typeof min !== "number" || typeof max !== "number") return null;
55136
- if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) return null;
55504
+ const timer = useDeviceCapability({
55505
+ trpc,
55506
+ deviceId,
55507
+ cap: (d) => d.timedRun,
55508
+ slice: (d) => d.state.timedRun
55509
+ });
55510
+ const { display, applyOptimistic } = useOptimisticSlice(slice, { enabled: optimistic ?? true });
55137
55511
  return {
55138
- min,
55139
- max
55512
+ cap,
55513
+ display,
55514
+ available,
55515
+ applyOptimistic,
55516
+ running: running.slice,
55517
+ power: power.slice,
55518
+ timer
55140
55519
  };
55141
55520
  }
55142
- /** Map a 0–1 drag fraction onto the setpoint, snapped to `tempStep`. */
55143
- function climateTargetFromFraction(fraction, bounds, tempStep) {
55144
- const step = resolveClimateTempStep(tempStep);
55145
- const clamped = Math.min(1, Math.max(0, fraction));
55146
- const raw = bounds.min + clamped * (bounds.max - bounds.min);
55147
- const steps = Math.round((raw - bounds.min) / step);
55148
- const snapped = bounds.min + steps * step;
55149
- const rounded = Math.round(snapped * 1e3) / 1e3;
55150
- return Math.min(bounds.max, Math.max(bounds.min, rounded));
55151
- }
55152
- /** AC-appropriate short mode labels. Exhaustive over HvacMode. */
55153
- function modeLabel(t, mode) {
55154
- switch (mode) {
55155
- case "cool": return t("uiLibrary.acPanel.modeCool", "Cool");
55156
- case "heat": return t("uiLibrary.acPanel.modeHeat", "Heat");
55157
- case "auto": return t("uiLibrary.acPanel.modeAuto", "Auto");
55158
- case "heat_cool": return t("uiLibrary.acPanel.modeHeatCool", "Heat·Cool");
55159
- case "fan_only": return t("uiLibrary.acPanel.modeFan", "Fan");
55160
- case "dry": return t("uiLibrary.acPanel.modeDry", "Dry");
55161
- case "off": return t("uiLibrary.acPanel.modeOff", "Off");
55162
- }
55521
+ function HeaterInlineControl(props) {
55522
+ const t = useUiText();
55523
+ const { cap, display, available, applyOptimistic, timer } = useHeater(props);
55524
+ if (cap === void 0 || display === void 0) return null;
55525
+ const on = display.on === true;
55526
+ const quickMinutes = HEATER_LIMIT === void 0 ? QUICK_RUN_MINUTES : Math.min(QUICK_RUN_MINUTES, maxInUnit(HEATER_LIMIT));
55527
+ return /* @__PURE__ */ jsxs("div", {
55528
+ className: "inline-flex items-center gap-2",
55529
+ children: [/* @__PURE__ */ jsx("span", {
55530
+ onClick: (e) => e.stopPropagation(),
55531
+ children: /* @__PURE__ */ jsx(Switch, {
55532
+ checked: on,
55533
+ disabled: !available,
55534
+ "aria-label": t("uiLibrary.heater.power", "Heater"),
55535
+ onCheckedChange: (next) => {
55536
+ applyOptimistic({ on: next });
55537
+ cap.setState({ on: next });
55538
+ }
55539
+ })
55540
+ }), timer.cap !== void 0 && /* @__PURE__ */ jsx("span", {
55541
+ onClick: (e) => e.stopPropagation(),
55542
+ children: /* @__PURE__ */ jsxs(Button, {
55543
+ size: "sm",
55544
+ variant: "outline",
55545
+ disabled: !timer.online,
55546
+ onClick: () => void timer.cap?.runFor({
55547
+ duration: quickMinutes,
55548
+ unit: "min"
55549
+ }),
55550
+ children: [/* @__PURE__ */ jsx(Timer, {
55551
+ className: "h-3.5 w-3.5",
55552
+ "aria-hidden": true
55553
+ }), t("uiLibrary.heater.quickRun", "Run {{minutes}} min", { minutes: quickMinutes })]
55554
+ })
55555
+ })]
55556
+ });
55163
55557
  }
55164
- /** Per-mode icon (lucide). Exhaustive over HvacMode. */
55165
- var MODE_ICON = {
55166
- cool: Snowflake,
55167
- heat: Flame,
55168
- auto: Sparkles,
55169
- heat_cool: Thermometer,
55170
- fan_only: Fan,
55171
- dry: Droplets,
55172
- off: Power
55173
- };
55174
- /** Mode accent hex — drives the airflow particles, the glow, and the target
55175
- * value colour. Mirrors the thermostat gauge palette. Exhaustive. */
55176
- var MODE_ACCENT = {
55177
- heat: "#f59e0b",
55178
- cool: "#60a5fa",
55179
- auto: "#c084fc",
55180
- heat_cool: "#e879f9",
55181
- fan_only: "#94a3b8",
55182
- dry: "#22d3ee",
55183
- off: "#a1a1aa"
55184
- };
55185
- /** Title-case a snake/lower token for a selector option ('medium_low' → 'Medium
55186
- * low', 'turbo' → 'Turbo'). Shared by the fan + preset selectors. */
55187
- function fanLabel(token) {
55188
- const spaced = token.replace(/_/g, " ");
55189
- return spaced.charAt(0).toUpperCase() + spaced.slice(1);
55558
+ function HeaterHeroCard(props) {
55559
+ const t = useUiText();
55560
+ const { cap, display, available, applyOptimistic, running, power, timer } = useHeater(props);
55561
+ if (cap === void 0 || display === void 0) return null;
55562
+ const on = display.on === true;
55563
+ const heating = running?.running ?? on;
55564
+ const watts = power?.power ?? null;
55565
+ return /* @__PURE__ */ jsxs("div", {
55566
+ className: "relative flex flex-col items-stretch gap-3 overflow-hidden rounded-lg border border-border bg-surface p-4",
55567
+ children: [
55568
+ /* @__PURE__ */ jsx("style", { children: KEYFRAMES$1 }),
55569
+ /* @__PURE__ */ jsxs("div", {
55570
+ className: "relative flex h-32 items-center justify-center overflow-hidden rounded-lg border border-border-subtle bg-background-elevated",
55571
+ children: [/* @__PURE__ */ jsx("div", {
55572
+ className: cn("pointer-events-none absolute inset-0", heating ? "opacity-60" : "opacity-20"),
55573
+ children: /* @__PURE__ */ jsx(AirflowViz, {
55574
+ mode: heating ? "heat" : "off",
55575
+ accent: HEAT_ACCENT,
55576
+ periodSec: HEAT_PERIOD_SEC,
55577
+ swaying: false,
55578
+ forceRising: true
55579
+ })
55580
+ }), /* @__PURE__ */ jsxs("div", {
55581
+ className: "relative z-10 flex flex-col items-center gap-1",
55582
+ children: [
55583
+ /* @__PURE__ */ jsx(Flame, {
55584
+ className: cn("h-8 w-8", heating ? "text-warning" : "text-foreground-subtle"),
55585
+ "aria-hidden": true
55586
+ }),
55587
+ /* @__PURE__ */ jsx("span", {
55588
+ className: "text-sm font-medium text-foreground",
55589
+ children: heating ? t("uiLibrary.heater.heating", "Heating") : t("uiLibrary.heater.off", "Off")
55590
+ }),
55591
+ /* @__PURE__ */ jsx("span", {
55592
+ className: "text-xs tabular-nums text-foreground-muted",
55593
+ "data-testid": "heater-watts",
55594
+ children: watts === null ? "—" : `${Math.round(watts)} W`
55595
+ })
55596
+ ]
55597
+ })]
55598
+ }),
55599
+ /* @__PURE__ */ jsxs("label", {
55600
+ className: "flex items-center justify-between gap-3 text-sm text-foreground",
55601
+ children: [t("uiLibrary.heater.power", "Heater"), /* @__PURE__ */ jsx(Switch, {
55602
+ checked: on,
55603
+ disabled: !available,
55604
+ onCheckedChange: (next) => {
55605
+ applyOptimistic({ on: next });
55606
+ cap.setState({ on: next });
55607
+ }
55608
+ })]
55609
+ }),
55610
+ timer.cap !== void 0 && HEATER_LIMIT !== void 0 && /* @__PURE__ */ jsx(TimedRunControl, {
55611
+ trpc: props.trpc,
55612
+ deviceId: props.deviceId,
55613
+ limit: HEATER_LIMIT
55614
+ })
55615
+ ]
55616
+ });
55190
55617
  }
55191
- /** Preset → icon. Unknown presets fall back to a neutral sparkle. */
55192
- function presetIcon(preset) {
55193
- switch (preset) {
55194
- case "turbo": return Zap;
55195
- case "quiet": return Feather;
55196
- case "sleep": return Moon;
55197
- case "eco": return Leaf;
55198
- case "8c_heat": return Snowflake;
55199
- case "none": return Ban;
55200
- default: return Sparkles;
55618
+ //#endregion
55619
+ //#region src/composites/device-controls/dishwasher-control.tsx
55620
+ /**
55621
+ * Dishwasher controls for a `DeviceType.Dishwasher` device.
55622
+ *
55623
+ * Reads the `dishwasher` cap status slice and renders inline + hero surfaces
55624
+ * mirroring vacuum-control / pet-feeder patterns.
55625
+ *
55626
+ * Salt and rinse aid are not here: they are items of the device's `consumables`
55627
+ * cap, shown by the page's Consumables section like every device's (D915).
55628
+ *
55629
+ * UNKNOWN IS NOT OFF. The slice carries `null` for everything the appliance has not
55630
+ * reported, and this view renders that as "—" / a disabled control, never as an unchecked
55631
+ * box or a zero. It also does not echo a command before the appliance confirms it: the
55632
+ * slice moves when the appliance says so.
55633
+ */
55634
+ /** What the operation state is called to a person, and how it is toned. */
55635
+ function dishwasherOperationMeta(operationState, t = defaultUiText) {
55636
+ switch (operationState) {
55637
+ case "Run": return {
55638
+ label: t("uiLibrary.dishwasher.op.run", "Running"),
55639
+ tone: "text-primary"
55640
+ };
55641
+ case "Pause": return {
55642
+ label: t("uiLibrary.dishwasher.op.pause", "Paused"),
55643
+ tone: "text-warning"
55644
+ };
55645
+ case "Finished": return {
55646
+ label: t("uiLibrary.dishwasher.op.finished", "Finished"),
55647
+ tone: "text-success"
55648
+ };
55649
+ case "Error": return {
55650
+ label: t("uiLibrary.dishwasher.op.error", "Error"),
55651
+ tone: "text-danger"
55652
+ };
55653
+ case "Aborting": return {
55654
+ label: t("uiLibrary.dishwasher.op.aborting", "Stopping"),
55655
+ tone: "text-warning"
55656
+ };
55657
+ case "ActionRequired": return {
55658
+ label: t("uiLibrary.dishwasher.op.actionRequired", "Action required"),
55659
+ tone: "text-warning"
55660
+ };
55661
+ case "DelayedStart": return {
55662
+ label: t("uiLibrary.dishwasher.op.delayedStart", "Delayed start"),
55663
+ tone: "text-primary"
55664
+ };
55665
+ case "Ready": return {
55666
+ label: t("uiLibrary.dishwasher.op.ready", "Ready"),
55667
+ tone: "text-foreground"
55668
+ };
55669
+ case "Inactive": return {
55670
+ label: t("uiLibrary.dishwasher.op.inactive", "Inactive"),
55671
+ tone: "text-foreground-subtle"
55672
+ };
55673
+ case null: return {
55674
+ label: t("uiLibrary.dishwasher.unknown", "Unknown"),
55675
+ tone: "text-foreground-subtle"
55676
+ };
55677
+ }
55678
+ }
55679
+ /** The headline for the whole slice: the appliance's state, or why there is none. */
55680
+ function dishwasherHeadline(status, t = defaultUiText) {
55681
+ switch (status.availability) {
55682
+ case "offline": return {
55683
+ label: t("uiLibrary.dishwasher.offline", "Offline"),
55684
+ tone: "text-foreground-subtle"
55685
+ };
55686
+ case "description-missing": return {
55687
+ label: t("uiLibrary.dishwasher.descriptionMissing", "Waiting for the appliance profile"),
55688
+ tone: "text-warning"
55689
+ };
55690
+ case "available": return dishwasherOperationMeta(status.operationState, t);
55201
55691
  }
55202
55692
  }
55693
+ /** Last segment of a feature key, spaced out: `Dishcare.Dishwasher.Program.Eco50` -> `Eco50`. */
55694
+ function featureLabel(key) {
55695
+ return (key.split(".").pop() ?? key).replace(/([a-z0-9])([A-Z])/g, "$1 $2");
55696
+ }
55203
55697
  /**
55204
- * Fan level → airflow animation period. Higher speed ⇒ shorter period. Unknown
55205
- * strings fall back to a medium pace. Turbo (a preset) shortens it further.
55698
+ * Salt and rinse aid are consumable items (D915). Their events must not
55699
+ * reappear on the hero — the Consumables section is the only surface.
55206
55700
  */
55207
- function airflowPeriodSec(fanMode) {
55208
- switch (fanMode) {
55209
- case "high": return 1;
55210
- case "medium_high": return 1.3;
55211
- case "medium": return 1.6;
55212
- case "medium_low": return 1.9;
55213
- case "low": return 2.2;
55214
- default: return 1.8;
55215
- }
55701
+ function isConsumableDishwasherEvent(event) {
55702
+ const short = (event.split(".").pop() ?? event).toLowerCase();
55703
+ return short.includes("salt") || short.includes("rinse");
55216
55704
  }
55217
- var KEYFRAMES = `
55218
- @keyframes acv-fall { 0%{transform:translateY(-1.75rem);opacity:0} 18%{opacity:.7} 82%{opacity:.7} 100%{transform:translateY(7.5rem);opacity:0} }
55219
- @keyframes acv-rise { 0%{transform:translateY(7.5rem);opacity:0} 18%{opacity:.7} 82%{opacity:.7} 100%{transform:translateY(-1.75rem);opacity:0} }
55220
- @keyframes acv-sway { 0%,100%{transform:translateX(-9%)} 50%{transform:translateX(9%)} }
55221
- @keyframes acv-swing-h { 0%,100%{transform:translateX(-22%)} 50%{transform:translateX(22%)} }
55222
- @keyframes acv-swing-v { 0%,100%{transform:translateY(-22%)} 50%{transform:translateY(22%)} }
55223
- @keyframes acv-spin { to { transform:rotate(360deg) } }
55224
- @keyframes acv-glow { 0%,100%{opacity:.35;transform:scale(1)} 50%{opacity:.6;transform:scale(1.06)} }
55225
- @media (prefers-reduced-motion: reduce) {
55226
- .acv-streak, .acv-fan, .acv-sway-wrap, .acv-glow, .acv-swing { animation: none !important; }
55705
+ /** Raised events the hero may name. Consumable events are dropped. */
55706
+ function visibleDishwasherEvents(events) {
55707
+ return events.filter((event) => !isConsumableDishwasherEvent(event));
55227
55708
  }
55228
- `;
55229
- function AcPanel({ trpc, deviceId, layout, optimistic }) {
55230
- const t = useUiText();
55231
- const { cap, slice, available } = useDeviceCapability({
55709
+ /** Whole seconds as a short duration: `1 h 24 min`, `42 min`, `30 s`. */
55710
+ function formatDuration(seconds, t = defaultUiText) {
55711
+ if (seconds < 60) return t("uiLibrary.dishwasher.durationSeconds", "{{n}} s", { n: seconds });
55712
+ const minutes = Math.round(seconds / 60);
55713
+ if (minutes < 60) return t("uiLibrary.dishwasher.durationMinutes", "{{n}} min", { n: minutes });
55714
+ const hours = Math.floor(minutes / 60);
55715
+ const rest = minutes % 60;
55716
+ return rest === 0 ? t("uiLibrary.dishwasher.durationHours", "{{n}} h", { n: hours }) : t("uiLibrary.dishwasher.durationHoursMinutes", "{{h}} h {{m}} min", {
55717
+ h: hours,
55718
+ m: rest
55719
+ });
55720
+ }
55721
+ function useDishwasher(trpc, deviceId) {
55722
+ return useDeviceCapability({
55232
55723
  trpc,
55233
55724
  deviceId,
55234
- cap: (d) => d.climateControl,
55235
- slice: (d) => d.state.climateControl
55725
+ cap: (d) => d.dishwasher,
55726
+ slice: (d) => d.state.dishwasher
55236
55727
  });
55237
- const { display, applyOptimistic } = useOptimisticSlice(slice, { enabled: optimistic ?? true });
55728
+ }
55729
+ function DishwasherIconButton({ label, busy, active, onClick, children }) {
55730
+ return /* @__PURE__ */ jsx("button", {
55731
+ type: "button",
55732
+ "aria-label": label,
55733
+ title: label,
55734
+ disabled: busy,
55735
+ onClick: (e) => {
55736
+ e.stopPropagation();
55737
+ onClick();
55738
+ },
55739
+ className: cn("inline-flex h-5 w-5 items-center justify-center rounded text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors", active && "bg-primary text-primary-foreground", busy && "opacity-40 cursor-not-allowed"),
55740
+ children
55741
+ });
55742
+ }
55743
+ function DishwasherGraphic({ running, progressPercent }) {
55744
+ const pct = progressPercent != null ? Math.max(0, Math.min(100, progressPercent)) : running ? 40 : 0;
55745
+ return /* @__PURE__ */ jsxs("div", {
55746
+ "aria-hidden": "true",
55747
+ className: "relative w-28 h-36 rounded border-2 border-border bg-gradient-to-b from-surface-hover to-surface overflow-hidden flex-shrink-0",
55748
+ children: [/* @__PURE__ */ jsx("div", {
55749
+ className: cn("absolute inset-x-0 bottom-0 bg-primary/25 transition-[height] duration-500", running && "animate-pulse"),
55750
+ style: { height: `${pct}%` }
55751
+ }), /* @__PURE__ */ jsx("div", {
55752
+ className: "absolute inset-0 flex items-center justify-center text-foreground-subtle",
55753
+ children: /* @__PURE__ */ jsx(Waves, { className: "h-10 w-10 opacity-70" })
55754
+ })]
55755
+ });
55756
+ }
55757
+ function DishwasherPanel({ trpc, deviceId, layout }) {
55758
+ const t = useUiText();
55759
+ const { cap, slice, available } = useDishwasher(trpc, deviceId);
55238
55760
  if (cap === void 0) return null;
55239
- if (display === void 0) return null;
55240
- const busy = !available;
55761
+ if (slice === void 0) return null;
55762
+ const display = slice;
55763
+ const link = display.availability === "available";
55764
+ const busy = !available || !link;
55765
+ const optionTogglesLocked = display.childLock === true;
55766
+ const meta = dishwasherHeadline(display, t);
55767
+ const running = display.operationState === "Run";
55768
+ const paused = display.operationState === "Pause";
55769
+ const startable = display.remoteStartAllowed === true && display.selectedProgram !== null;
55770
+ const press = (fn) => {
55771
+ if (busy) return;
55772
+ fn();
55773
+ };
55241
55774
  if (layout === "compact") return /* @__PURE__ */ jsxs("div", {
55242
- "data-mode": display.mode,
55243
- className: "inline-flex items-center gap-1",
55775
+ className: "inline-flex items-center gap-1.5 max-w-full",
55244
55776
  children: [
55777
+ display.doorOpen === true && /* @__PURE__ */ jsx("span", {
55778
+ className: "inline-flex text-warning shrink-0",
55779
+ title: t("uiLibrary.dishwasher.doorOpen", "Door open"),
55780
+ "aria-label": t("uiLibrary.dishwasher.doorOpen", "Door open"),
55781
+ children: /* @__PURE__ */ jsx(DoorOpen, { className: "h-3.5 w-3.5" })
55782
+ }),
55245
55783
  /* @__PURE__ */ jsx("span", {
55246
- className: cn("text-xs tabular-nums font-medium", MODE_TEXT_COLOR[display.mode]),
55247
- children: display.target !== null ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
55248
- display.target,
55249
- "°",
55250
- display.currentTemp !== null && /* @__PURE__ */ jsxs("span", {
55251
- className: "text-foreground-subtle font-normal",
55252
- children: [
55253
- " ",
55254
- "(",
55255
- display.currentTemp,
55256
- "°)"
55257
- ]
55258
- })
55259
- ] }) : display.currentTemp !== null ? /* @__PURE__ */ jsxs("span", {
55260
- className: "text-foreground-subtle",
55261
- children: [display.currentTemp, "°"]
55262
- }) : null
55784
+ className: cn("text-xs font-medium tabular-nums shrink-0", meta.tone),
55785
+ children: meta.label
55263
55786
  }),
55264
- display.target !== null && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
55265
- type: "button",
55266
- "aria-label": t("uiLibrary.acPanel.decrease", "Decrease target"),
55267
- disabled: busy,
55268
- onClick: (e) => {
55269
- e.stopPropagation();
55270
- if (!busy && display.target !== null) {
55271
- const next = nextClimateTarget(display.target, -1, display);
55272
- applyOptimistic({ target: next });
55273
- cap.setTarget({ target: next });
55274
- }
55275
- },
55276
- className: cn("inline-flex h-5 w-5 items-center justify-center rounded text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors text-xs", busy && "opacity-40 cursor-not-allowed"),
55277
- children: "−"
55278
- }), /* @__PURE__ */ jsx("button", {
55279
- type: "button",
55280
- "aria-label": t("uiLibrary.acPanel.increase", "Increase target"),
55281
- disabled: busy,
55282
- onClick: (e) => {
55283
- e.stopPropagation();
55284
- if (!busy && display.target !== null) {
55285
- const next = nextClimateTarget(display.target, 1, display);
55286
- applyOptimistic({ target: next });
55287
- cap.setTarget({ target: next });
55288
- }
55289
- },
55290
- className: cn("inline-flex h-5 w-5 items-center justify-center rounded text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors text-xs", busy && "opacity-40 cursor-not-allowed"),
55291
- children: "+"
55292
- })] }),
55293
- /* @__PURE__ */ jsx("select", {
55294
- "aria-label": t("uiLibrary.acPanel.mode", "Mode"),
55295
- value: display.mode,
55296
- disabled: busy,
55297
- onChange: (e) => {
55298
- e.stopPropagation();
55299
- const mode = display.availableModes.find((m) => m === e.target.value);
55300
- if (!busy && mode) {
55301
- applyOptimistic({ mode });
55302
- cap.setMode({ mode });
55303
- }
55304
- },
55305
- className: cn("bg-transparent px-0.5 text-xs text-foreground-subtle hover:text-foreground cursor-pointer", busy && "opacity-40 cursor-not-allowed"),
55306
- children: display.availableModes.map((m) => /* @__PURE__ */ jsx("option", {
55307
- value: m,
55308
- children: modeLabel(t, m)
55309
- }, m))
55787
+ display.program != null && /* @__PURE__ */ jsx("span", {
55788
+ className: "text-xs text-foreground-subtle truncate max-w-[7rem]",
55789
+ title: display.program,
55790
+ children: featureLabel(display.program)
55791
+ }),
55792
+ display.remaining != null && /* @__PURE__ */ jsxs("span", {
55793
+ className: "inline-flex items-center gap-0.5 text-xs text-foreground-subtle tabular-nums shrink-0",
55794
+ children: [/* @__PURE__ */ jsx(Timer, { className: "h-3 w-3" }), formatDuration(display.remaining, t)]
55795
+ }),
55796
+ /* @__PURE__ */ jsx(DishwasherIconButton, {
55797
+ label: t("uiLibrary.dishwasher.start", "Start"),
55798
+ busy: busy || !startable,
55799
+ active: running,
55800
+ onClick: () => press(() => cap.start({})),
55801
+ children: /* @__PURE__ */ jsx(Play, { className: "h-3 w-3" })
55802
+ }),
55803
+ /* @__PURE__ */ jsx(DishwasherIconButton, {
55804
+ label: paused ? t("uiLibrary.dishwasher.resume", "Resume") : t("uiLibrary.dishwasher.pause", "Pause"),
55805
+ busy: busy || !(running || paused),
55806
+ active: paused,
55807
+ onClick: () => press(() => paused ? cap.resume({}) : cap.pause({})),
55808
+ children: /* @__PURE__ */ jsx(Pause, { className: "h-3 w-3" })
55310
55809
  })
55311
55810
  ]
55312
55811
  });
55313
- const accent = MODE_ACCENT[display.mode];
55314
- const on = display.mode !== "off";
55315
- const heatingOnly = !climateOffersCooling(display.availableModes);
55316
- const setpointBounds = climateSetpointBounds(display);
55317
- const CurrentPresetIcon = presetIcon(display.preset);
55318
- const boost = display.preset === "turbo";
55319
- const period = Math.max(.55, airflowPeriodSec(display.fanMode) * (boost ? .6 : 1));
55320
- const showVSwing = display.swingVertical !== null;
55321
- const showHSwing = display.swingHorizontal !== null;
55322
- const swaying = on && (display.swingVertical === true || display.swingHorizontal === true);
55812
+ const programs = display.availablePrograms;
55323
55813
  return /* @__PURE__ */ jsxs("div", {
55324
- "data-mode": display.mode,
55325
- className: cn("relative flex flex-col items-stretch gap-2.5 overflow-hidden rounded-lg border p-3 transition-colors", MODE_COLOR[display.mode]),
55814
+ className: "flex flex-col gap-3 rounded-lg border border-border bg-surface p-4",
55326
55815
  children: [
55327
- /* @__PURE__ */ jsx("style", { children: KEYFRAMES }),
55328
55816
  /* @__PURE__ */ jsxs("div", {
55329
- className: "relative z-10 flex flex-col items-center justify-center gap-1 overflow-hidden rounded-lg border border-border/50 bg-surface/30 px-3 py-3",
55330
- children: [
55331
- /* @__PURE__ */ jsx("div", {
55332
- className: "pointer-events-none absolute inset-0 opacity-60",
55333
- children: heatingOnly && !on ? /* @__PURE__ */ jsx(RadiatorFins, {}) : /* @__PURE__ */ jsx(AirflowViz, {
55334
- mode: display.mode,
55335
- accent,
55336
- periodSec: period,
55337
- swaying,
55338
- forceRising: heatingOnly
55339
- })
55340
- }),
55341
- /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 bg-gradient-to-b from-surface/50 via-transparent to-surface/50" }),
55342
- on && /* @__PURE__ */ jsx("span", {
55343
- "aria-hidden": true,
55344
- className: "acv-glow pointer-events-none absolute left-1/2 top-1/2 h-16 w-16 -translate-x-1/2 -translate-y-1/2 rounded-full blur-2xl",
55345
- style: {
55346
- background: accent,
55347
- animation: "acv-glow 3.2s ease-in-out infinite"
55348
- }
55349
- }),
55350
- /* @__PURE__ */ jsxs("div", {
55351
- className: "relative z-10 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide",
55352
- style: { color: accent },
55353
- children: [
55354
- /* @__PURE__ */ jsx(ModeIcon, {
55355
- mode: display.mode,
55356
- heatingOnly,
55357
- className: "h-3.5 w-3.5"
55358
- }),
55359
- modeLabel(t, display.mode),
55360
- display.currentTemp !== null && /* @__PURE__ */ jsx("span", {
55361
- className: "normal-case text-foreground-subtle",
55362
- children: t("uiLibrary.acPanel.now", "· {{temp}}° now", { temp: display.currentTemp })
55363
- }),
55364
- display.currentHumidity !== null && /* @__PURE__ */ jsxs("span", {
55365
- className: "inline-flex items-center gap-0.5 normal-case text-foreground-subtle",
55366
- children: [
55367
- /* @__PURE__ */ jsx(Droplets, { className: "h-3 w-3" }),
55368
- display.currentHumidity,
55369
- "%"
55370
- ]
55371
- })
55372
- ]
55373
- }),
55374
- display.target !== null ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
55375
- className: "relative z-10 flex items-center gap-3",
55376
- children: [
55377
- /* @__PURE__ */ jsx(RoundStep, {
55378
- label: t("uiLibrary.acPanel.decrease", "Decrease target"),
55379
- symbol: "−",
55380
- disabled: busy,
55381
- onClick: () => {
55382
- if (busy || display.target === null) return;
55383
- const next = nextClimateTarget(display.target, -1, display);
55384
- applyOptimistic({ target: next });
55385
- cap.setTarget({ target: next });
55386
- }
55387
- }),
55388
- /* @__PURE__ */ jsxs("div", {
55389
- className: "flex items-baseline gap-0.5",
55390
- children: [/* @__PURE__ */ jsx("span", {
55391
- className: cn("text-4xl font-bold leading-none tabular-nums", climateTargetWidthClass(display)),
55392
- style: { color: accent },
55393
- children: display.target
55394
- }), /* @__PURE__ */ jsx("span", {
55395
- className: "text-lg text-foreground-subtle",
55396
- children: "°"
55397
- })]
55398
- }),
55399
- /* @__PURE__ */ jsx(RoundStep, {
55400
- label: t("uiLibrary.acPanel.increase", "Increase target"),
55401
- symbol: "+",
55402
- disabled: busy,
55403
- onClick: () => {
55404
- if (busy || display.target === null) return;
55405
- const next = nextClimateTarget(display.target, 1, display);
55406
- applyOptimistic({ target: next });
55407
- cap.setTarget({ target: next });
55408
- }
55409
- })
55410
- ]
55411
- }), setpointBounds !== null && /* @__PURE__ */ jsx("div", {
55412
- className: "relative z-10 w-full px-1",
55413
- children: /* @__PURE__ */ jsx(RangeTrack, {
55414
- value: display.target,
55415
- min: setpointBounds.min,
55416
- max: setpointBounds.max,
55417
- step: display.tempStep,
55418
- accent,
55419
- disabled: busy,
55420
- label: t("uiLibrary.acPanel.setpoint", "Setpoint"),
55421
- onPreview: (next) => {
55422
- applyOptimistic({ target: next });
55423
- },
55424
- onCommit: (next) => {
55425
- applyOptimistic({ target: next });
55426
- cap.setTarget({ target: next });
55427
- }
55817
+ className: "flex items-start gap-4",
55818
+ children: [/* @__PURE__ */ jsx(DishwasherGraphic, {
55819
+ running,
55820
+ progressPercent: display.progress
55821
+ }), /* @__PURE__ */ jsxs("div", {
55822
+ className: "flex min-w-0 flex-1 flex-col gap-2",
55823
+ children: [
55824
+ /* @__PURE__ */ jsxs("div", {
55825
+ className: "flex flex-wrap items-center gap-2",
55826
+ children: [/* @__PURE__ */ jsx("span", {
55827
+ className: cn("text-3xl font-semibold", meta.tone),
55828
+ children: meta.label
55829
+ }), display.powerOn === false && /* @__PURE__ */ jsx("span", {
55830
+ className: "text-xs font-medium text-foreground-subtle",
55831
+ children: t("uiLibrary.dishwasher.powerOff", "Power off")
55832
+ })]
55833
+ }),
55834
+ display.program != null && /* @__PURE__ */ jsx("span", {
55835
+ className: "text-sm text-foreground-subtle",
55836
+ title: display.program,
55837
+ children: featureLabel(display.program)
55838
+ }),
55839
+ display.remaining != null && /* @__PURE__ */ jsxs("span", {
55840
+ className: "inline-flex items-center gap-1 text-sm text-foreground-subtle tabular-nums",
55841
+ children: [/* @__PURE__ */ jsx(Timer, { className: "h-3.5 w-3.5" }), t("uiLibrary.dishwasher.remaining", "{{time}} left", { time: formatDuration(display.remaining, t) })]
55842
+ }),
55843
+ display.delayedStart != null && display.delayedStart > 0 && /* @__PURE__ */ jsx("span", {
55844
+ className: "text-xs text-foreground-subtle tabular-nums",
55845
+ children: t("uiLibrary.dishwasher.startsIn", "Starts in {{time}}", { time: formatDuration(display.delayedStart, t) })
55846
+ }),
55847
+ display.progress != null && /* @__PURE__ */ jsxs("div", {
55848
+ className: "flex items-center gap-2",
55849
+ children: [/* @__PURE__ */ jsx("div", {
55850
+ className: "h-1.5 flex-1 rounded bg-surface-hover overflow-hidden",
55851
+ children: /* @__PURE__ */ jsx("div", {
55852
+ className: "h-full bg-primary transition-[width] duration-500",
55853
+ style: { width: `${Math.max(0, Math.min(100, display.progress))}%` }
55854
+ })
55855
+ }), /* @__PURE__ */ jsxs("span", {
55856
+ className: "tabular-nums text-xs text-foreground-subtle",
55857
+ children: [Math.round(display.progress), "%"]
55858
+ })]
55859
+ }),
55860
+ /* @__PURE__ */ jsxs("div", {
55861
+ className: "flex flex-wrap items-center gap-x-3 gap-y-1.5",
55862
+ children: [display.doorOpen === true && /* @__PURE__ */ jsxs("span", {
55863
+ className: "inline-flex items-center gap-1 text-xs text-warning",
55864
+ children: [/* @__PURE__ */ jsx(DoorOpen, { className: "h-3.5 w-3.5" }), t("uiLibrary.dishwasher.doorOpen", "Door open")]
55865
+ }), visibleDishwasherEvents(display.activeEvents).map((event) => /* @__PURE__ */ jsx("span", {
55866
+ className: "text-xs text-warning",
55867
+ title: event,
55868
+ children: featureLabel(event)
55869
+ }, event))]
55870
+ }),
55871
+ display.operationState === "Error" && /* @__PURE__ */ jsxs("div", {
55872
+ className: "inline-flex items-center gap-1 text-xs text-danger",
55873
+ children: [/* @__PURE__ */ jsx(TriangleAlert, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ jsx("span", { children: display.errorLabel != null ? featureLabel(display.errorLabel) : display.errorCode != null ? t("uiLibrary.dishwasher.errorCode", "Error {{code}}", { code: display.errorCode }) : t("uiLibrary.dishwasher.op.error", "Error") })]
55874
+ }),
55875
+ /* @__PURE__ */ jsxs("div", {
55876
+ className: "flex flex-wrap items-center gap-2",
55877
+ children: [
55878
+ /* @__PURE__ */ jsx(DishwasherIconButton, {
55879
+ label: t("uiLibrary.dishwasher.start", "Start"),
55880
+ busy: busy || !startable,
55881
+ active: running,
55882
+ onClick: () => press(() => cap.start({})),
55883
+ children: /* @__PURE__ */ jsx(Play, { className: "h-4 w-4" })
55884
+ }),
55885
+ /* @__PURE__ */ jsx(DishwasherIconButton, {
55886
+ label: paused ? t("uiLibrary.dishwasher.resume", "Resume") : t("uiLibrary.dishwasher.pause", "Pause"),
55887
+ busy: busy || !(running || paused),
55888
+ active: paused,
55889
+ onClick: () => press(() => paused ? cap.resume({}) : cap.pause({})),
55890
+ children: /* @__PURE__ */ jsx(Pause, { className: "h-4 w-4" })
55891
+ }),
55892
+ /* @__PURE__ */ jsx(DishwasherIconButton, {
55893
+ label: t("uiLibrary.dishwasher.stop", "Stop"),
55894
+ busy: busy || !(running || paused),
55895
+ active: false,
55896
+ onClick: () => press(() => cap.stop({})),
55897
+ children: /* @__PURE__ */ jsx(Square, { className: "h-3.5 w-3.5" })
55898
+ }),
55899
+ /* @__PURE__ */ jsx(DishwasherIconButton, {
55900
+ label: t("uiLibrary.dishwasher.power", "Power"),
55901
+ busy: busy || display.powerOn === null,
55902
+ active: display.powerOn === true,
55903
+ onClick: () => {
55904
+ const next = display.powerOn !== true;
55905
+ press(() => cap.setPower({ on: next }));
55906
+ },
55907
+ children: /* @__PURE__ */ jsx(Power, { className: "h-4 w-4" })
55908
+ })
55909
+ ]
55428
55910
  })
55429
- })] }) : /* @__PURE__ */ jsxs("div", {
55430
- className: "relative z-10 flex items-baseline gap-0.5",
55431
- children: [/* @__PURE__ */ jsx("span", {
55432
- className: cn("text-4xl font-bold leading-none tabular-nums text-foreground", climateTargetWidthClass(display)),
55433
- children: display.currentTemp ?? "—"
55434
- }), /* @__PURE__ */ jsx("span", {
55435
- className: "text-lg text-foreground-subtle",
55436
- children: "°"
55437
- })]
55438
- })
55439
- ]
55911
+ ]
55912
+ })]
55913
+ }),
55914
+ programs.length > 0 && /* @__PURE__ */ jsxs("label", {
55915
+ className: "flex items-center gap-2 text-xs text-foreground-subtle",
55916
+ children: [/* @__PURE__ */ jsx("span", {
55917
+ className: "w-16 shrink-0",
55918
+ children: t("uiLibrary.dishwasher.program", "Program")
55919
+ }), /* @__PURE__ */ jsxs("select", {
55920
+ "aria-label": t("uiLibrary.dishwasher.program", "Program"),
55921
+ value: display.selectedProgram ?? "",
55922
+ disabled: busy,
55923
+ onChange: (e) => {
55924
+ const program = e.target.value;
55925
+ if (!program) return;
55926
+ cap.setProgram({ program });
55927
+ },
55928
+ onClick: (e) => {
55929
+ e.stopPropagation();
55930
+ },
55931
+ className: "flex-1 rounded border border-border bg-surface px-2 py-1 text-foreground disabled:opacity-50",
55932
+ children: [display.selectedProgram == null && /* @__PURE__ */ jsx("option", {
55933
+ value: "",
55934
+ children: "—"
55935
+ }), programs.map((p) => /* @__PURE__ */ jsx("option", {
55936
+ value: p,
55937
+ children: featureLabel(p)
55938
+ }, p))]
55939
+ })]
55440
55940
  }),
55441
55941
  /* @__PURE__ */ jsxs("div", {
55442
- className: "relative z-10 grid grid-cols-3 gap-2",
55942
+ className: "flex flex-wrap gap-4 text-xs",
55443
55943
  children: [
55444
- /* @__PURE__ */ jsx(CompactSelect, {
55445
- label: t("uiLibrary.acPanel.mode", "Mode"),
55446
- icon: /* @__PURE__ */ jsx("span", {
55447
- style: { color: accent },
55448
- className: "flex",
55449
- children: /* @__PURE__ */ jsx(ModeIcon, {
55450
- mode: display.mode,
55451
- heatingOnly,
55452
- className: "h-4 w-4"
55453
- })
55454
- }),
55455
- value: display.mode,
55456
- options: display.availableModes.map((m) => ({
55457
- value: m,
55458
- label: modeLabel(t, m)
55459
- })),
55460
- disabled: busy,
55461
- onChange: (v) => {
55462
- const mode = display.availableModes.find((m) => m === v);
55463
- if (mode) {
55464
- applyOptimistic({ mode });
55465
- cap.setMode({ mode });
55466
- }
55467
- }
55944
+ /* @__PURE__ */ jsx(ToggleRow, {
55945
+ label: t("uiLibrary.dishwasher.halfLoad", "Half load"),
55946
+ checked: display.halfLoad,
55947
+ shown: link,
55948
+ busy: busy || optionTogglesLocked,
55949
+ onChange: (on) => void cap.setHalfLoad({ on })
55950
+ }),
55951
+ /* @__PURE__ */ jsx(ToggleRow, {
55952
+ label: t("uiLibrary.dishwasher.hygienePlus", "Hygiene plus"),
55953
+ checked: display.hygienePlus,
55954
+ shown: link,
55955
+ busy: busy || optionTogglesLocked,
55956
+ onChange: (on) => void cap.setHygienePlus({ on })
55957
+ }),
55958
+ /* @__PURE__ */ jsx(ToggleRow, {
55959
+ label: t("uiLibrary.dishwasher.extraDry", "Extra dry"),
55960
+ checked: display.extraDry,
55961
+ shown: link,
55962
+ busy: busy || optionTogglesLocked,
55963
+ onChange: (on) => void cap.setExtraDry({ on })
55964
+ }),
55965
+ /* @__PURE__ */ jsx(ToggleRow, {
55966
+ label: t("uiLibrary.dishwasher.intensiveZone", "Intensive zone"),
55967
+ checked: display.intensiveZone,
55968
+ shown: link,
55969
+ busy: busy || optionTogglesLocked,
55970
+ onChange: (on) => void cap.setIntensiveZone({ on })
55468
55971
  }),
55469
- display.availableFanModes.length > 0 && /* @__PURE__ */ jsx(CompactSelect, {
55470
- label: t("uiLibrary.acPanel.fan", "Fan"),
55471
- icon: /* @__PURE__ */ jsx(Wind, { className: "h-4 w-4 text-sky-500" }),
55472
- value: display.fanMode,
55473
- options: display.availableFanModes.map((f) => ({
55474
- value: f,
55475
- label: fanLabel(f)
55476
- })),
55477
- disabled: busy,
55478
- onChange: (v) => {
55479
- applyOptimistic({ fanMode: v });
55480
- cap.setFanMode({ fanMode: v });
55481
- }
55972
+ /* @__PURE__ */ jsx(ToggleRow, {
55973
+ label: t("uiLibrary.dishwasher.varioSpeedPlus", "VarioSpeed+"),
55974
+ checked: display.varioSpeedPlus,
55975
+ shown: link,
55976
+ busy: busy || optionTogglesLocked,
55977
+ onChange: (on) => void cap.setVarioSpeedPlus({ on })
55482
55978
  }),
55483
- display.availablePresets.length > 0 && /* @__PURE__ */ jsx(CompactSelect, {
55484
- label: t("uiLibrary.acPanel.preset", "Preset"),
55485
- icon: /* @__PURE__ */ jsx(CurrentPresetIcon, { className: "h-4 w-4 text-emerald-500" }),
55486
- value: display.preset,
55487
- options: display.availablePresets.map((p) => ({
55488
- value: p,
55489
- label: fanLabel(p)
55490
- })),
55491
- disabled: busy,
55492
- onChange: (v) => {
55493
- applyOptimistic({ preset: v });
55494
- cap.setPreset({ preset: v });
55495
- }
55979
+ /* @__PURE__ */ jsx(ToggleRow, {
55980
+ label: t("uiLibrary.dishwasher.childLock", "Child lock"),
55981
+ checked: display.childLock,
55982
+ shown: link,
55983
+ busy,
55984
+ onChange: (on) => void cap.setChildLock({ on })
55496
55985
  })
55497
55986
  ]
55498
- }),
55499
- (showVSwing || showHSwing) && /* @__PURE__ */ jsx(Field, {
55500
- label: t("uiLibrary.acPanel.swing", "Swing"),
55501
- children: /* @__PURE__ */ jsxs("div", {
55502
- className: "grid grid-cols-2 gap-1",
55503
- children: [showVSwing && /* @__PURE__ */ jsx(SwingToggle, {
55504
- axis: "vertical",
55505
- on: display.swingVertical ?? false,
55506
- busy,
55507
- onToggle: (next) => {
55508
- applyOptimistic({ swingVertical: next });
55509
- cap.setSwingVertical({ on: next });
55510
- }
55511
- }), showHSwing && /* @__PURE__ */ jsx(SwingToggle, {
55512
- axis: "horizontal",
55513
- on: display.swingHorizontal ?? false,
55514
- busy,
55515
- onToggle: (next) => {
55516
- applyOptimistic({ swingHorizontal: next });
55517
- cap.setSwingHorizontal({ on: next });
55518
- }
55519
- })]
55520
- })
55521
55987
  })
55522
55988
  ]
55523
55989
  });
55524
55990
  }
55525
- /** Labelled control group — a small uppercase header above its control. */
55526
- function Field({ label, children }) {
55527
- return /* @__PURE__ */ jsxs("div", {
55528
- className: "relative z-10 flex flex-col gap-1",
55529
- children: [/* @__PURE__ */ jsx("span", {
55530
- className: "text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle",
55531
- children: label
55532
- }), children]
55991
+ /**
55992
+ * One boolean setting. `checked === null` is "the appliance has not said": on a reachable
55993
+ * appliance that means it does not offer the setting (hidden); on an unreachable one the
55994
+ * setting is shown but disabled and marked unknown — never as an unchecked box.
55995
+ */
55996
+ function ToggleRow({ label, checked, shown, busy, onChange }) {
55997
+ const t = useUiText();
55998
+ if (checked === null && shown) return null;
55999
+ return /* @__PURE__ */ jsxs("label", {
56000
+ className: "inline-flex items-center gap-2 cursor-pointer",
56001
+ children: [
56002
+ /* @__PURE__ */ jsx("input", {
56003
+ type: "checkbox",
56004
+ checked: checked === true,
56005
+ "aria-checked": checked === null ? "mixed" : checked,
56006
+ disabled: busy || checked === null,
56007
+ onChange: (e) => {
56008
+ onChange(e.target.checked);
56009
+ },
56010
+ onClick: (e) => {
56011
+ e.stopPropagation();
56012
+ },
56013
+ className: "rounded border-border"
56014
+ }),
56015
+ /* @__PURE__ */ jsx("span", { children: label }),
56016
+ checked === null && /* @__PURE__ */ jsx("span", {
56017
+ className: "text-foreground-subtle",
56018
+ children: t("uiLibrary.dishwasher.unknownValue", "—")
56019
+ })
56020
+ ]
55533
56021
  });
55534
56022
  }
55535
- function ModeIcon({ mode, heatingOnly = false, className }) {
55536
- return /* @__PURE__ */ jsx(heatingOnly && mode === "heat" ? Heater : MODE_ICON[mode], {
55537
- className,
55538
- "aria-hidden": true
56023
+ function DishwasherInlineControl(props) {
56024
+ return /* @__PURE__ */ jsx(DishwasherPanel, {
56025
+ ...props,
56026
+ layout: "compact"
55539
56027
  });
55540
56028
  }
55541
- /** Compact labelled dropdown — a leading icon + native `<select>` + chevron,
55542
- * used for the Mode / Fan / Preset selectors so all three fit in one row. */
55543
- function CompactSelect({ label, icon, value, options, disabled, onChange }) {
55544
- return /* @__PURE__ */ jsxs("div", {
55545
- className: "flex min-w-0 flex-col gap-1",
55546
- children: [/* @__PURE__ */ jsx("span", {
55547
- className: "text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle",
55548
- children: label
55549
- }), /* @__PURE__ */ jsxs("div", {
55550
- className: cn("flex items-center gap-1 overflow-hidden rounded-lg border border-border/60 bg-surface-subtle px-1.5 py-1.5 has-[:focus-visible]:border-primary", disabled && "opacity-40"),
55551
- children: [
55552
- /* @__PURE__ */ jsx("span", {
55553
- className: "flex shrink-0",
55554
- children: icon
55555
- }),
55556
- /* @__PURE__ */ jsx("select", {
55557
- "aria-label": label,
55558
- value,
55559
- disabled,
55560
- onChange: (e) => {
55561
- e.stopPropagation();
55562
- if (!disabled) onChange(e.target.value);
55563
- },
55564
- className: "min-w-0 flex-1 cursor-pointer appearance-none truncate bg-transparent text-xs font-medium text-foreground outline-none",
55565
- children: options.map((o) => /* @__PURE__ */ jsx("option", {
55566
- value: o.value,
55567
- children: o.label
55568
- }, o.value))
55569
- }),
55570
- /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3 shrink-0 text-foreground-subtle" })
55571
- ]
55572
- })]
56029
+ function DishwasherHeroCard(props) {
56030
+ return /* @__PURE__ */ jsx(DishwasherPanel, {
56031
+ ...props,
56032
+ layout: "full"
55573
56033
  });
55574
56034
  }
55575
- /** Circular ± button for the target. */
55576
- function RoundStep({ label, symbol, disabled, onClick }) {
55577
- return /* @__PURE__ */ jsx("button", {
55578
- type: "button",
55579
- "aria-label": label,
55580
- disabled,
55581
- onClick,
55582
- className: cn("flex h-8 w-8 shrink-0 items-center justify-center rounded-full border border-border bg-surface text-lg leading-none text-foreground-subtle transition-colors hover:bg-surface-hover hover:text-foreground active:scale-95", disabled && "opacity-40 cursor-not-allowed"),
55583
- children: symbol
55584
- });
56035
+ //#endregion
56036
+ //#region src/composites/device-controls/appliance-control.tsx
56037
+ /**
56038
+ * Appliance card for a `DeviceType.Washer` / `DeviceType.Dryer` device.
56039
+ *
56040
+ * These appliances have no program surface: what is worth showing is whether
56041
+ * the cycle is running (the `running-state` cap), for how long, and what the
56042
+ * appliance draws right now (the `power-meter` cap). Both slices are read
56043
+ * straight from the device; neither is required.
56044
+ * - ApplianceInlineControl (device-list row): the running badge round the
56045
+ * drum icon, plus the live watts when there are any.
56046
+ * - ApplianceHeroCard (device-detail hero): the drum (turning only while a
56047
+ * cycle runs), the state, the phase, the dwell and the power.
56048
+ *
56049
+ * UNKNOWN IS NOT OFF (D393). `running: null` is drawn as "Unknown" and the
56050
+ * drum stays still and unbadged; a missing watt reading is a dash, never
56051
+ * "0 W". A slice that has not landed hides its row instead of faking a value.
56052
+ */
56053
+ var KEYFRAMES = `
56054
+ @keyframes apl-tumble { to { transform: rotate(360deg) } }
56055
+ .apl-drum-run { animation: apl-tumble 3s linear infinite; }
56056
+ @media (prefers-reduced-motion: reduce) {
56057
+ .apl-drum-run { animation: none !important; }
55585
56058
  }
55586
- /** Setpoint track. Drag previews; the command is sent when the pointer is released. */
55587
- function RangeTrack({ value, min, max, step, accent, disabled, label, onPreview, onCommit }) {
55588
- const trackRef = useRef(null);
55589
- const draggingRef = useRef(false);
55590
- const [draft, setDraft] = useState(null);
55591
- const shown = draft ?? value;
55592
- const pct = `${Math.min(1, Math.max(0, (shown - min) / (max - min))) * 100}%`;
55593
- const tempAt = (clientX) => {
55594
- const el = trackRef.current;
55595
- if (el === null) return value;
55596
- const rect = el.getBoundingClientRect();
55597
- if (rect.width <= 0) return value;
55598
- return climateTargetFromFraction((clientX - rect.left) / rect.width, {
55599
- min,
55600
- max
55601
- }, step);
55602
- };
55603
- const onPointerDown = (event) => {
55604
- if (disabled) return;
55605
- event.stopPropagation();
55606
- event.preventDefault();
55607
- draggingRef.current = true;
55608
- if (typeof event.currentTarget.setPointerCapture === "function") event.currentTarget.setPointerCapture(event.pointerId);
55609
- const next = tempAt(event.clientX);
55610
- setDraft(next);
55611
- onPreview(next);
56059
+ `;
56060
+ /** Whole watts, or a dash when the appliance has not reported a reading. */
56061
+ function formatWatts(power) {
56062
+ return power === void 0 || !Number.isFinite(power) ? "—" : `${Math.round(power)} W`;
56063
+ }
56064
+ /** The state to a person: running / idle, or why there is none (unknown). */
56065
+ function applianceStateLabel(running, t) {
56066
+ if (running === true) return {
56067
+ label: t("uiLibrary.appliance.running", "Running"),
56068
+ tone: "text-primary"
55612
56069
  };
55613
- const onPointerMove = (event) => {
55614
- if (disabled || !draggingRef.current) return;
55615
- event.stopPropagation();
55616
- const next = tempAt(event.clientX);
55617
- setDraft(next);
55618
- onPreview(next);
56070
+ if (running === false) return {
56071
+ label: t("uiLibrary.appliance.idle", "Idle"),
56072
+ tone: "text-foreground"
55619
56073
  };
55620
- const endDrag = (event) => {
55621
- if (!draggingRef.current) return;
55622
- event.stopPropagation();
55623
- draggingRef.current = false;
55624
- const next = tempAt(event.clientX);
55625
- setDraft(null);
55626
- if (event.currentTarget.hasPointerCapture?.(event.pointerId) === true) event.currentTarget.releasePointerCapture(event.pointerId);
55627
- onCommit(next);
56074
+ return {
56075
+ label: t("uiLibrary.appliance.unknown", "Unknown"),
56076
+ tone: "text-foreground-subtle"
55628
56077
  };
55629
- const onKeyDown = (event) => {
55630
- if (disabled) return;
55631
- const current = draft ?? value;
55632
- if (event.key === "ArrowRight" || event.key === "ArrowUp") {
55633
- event.preventDefault();
55634
- onCommit(nextClimateTarget(current, 1, {
55635
- tempStep: step,
55636
- minTemp: min,
55637
- maxTemp: max
55638
- }));
55639
- } else if (event.key === "ArrowLeft" || event.key === "ArrowDown") {
55640
- event.preventDefault();
55641
- onCommit(nextClimateTarget(current, -1, {
55642
- tempStep: step,
55643
- minTemp: min,
55644
- maxTemp: max
55645
- }));
55646
- } else if (event.key === "Home") {
55647
- event.preventDefault();
55648
- onCommit(min);
55649
- } else if (event.key === "End") {
55650
- event.preventDefault();
55651
- onCommit(max);
55652
- }
56078
+ }
56079
+ function dwellText(running, since, now, t) {
56080
+ if (running !== true) return null;
56081
+ const { duration } = runningStatusParts(running, since, null, now);
56082
+ if (duration === void 0) return null;
56083
+ return "minutes" in duration ? t("uiLibrary.appliance.forMinutes", "for {{count}} min", { count: duration.minutes }) : t("uiLibrary.appliance.forHours", "for {{count}} h", { count: duration.hours });
56084
+ }
56085
+ function useApplianceState(props) {
56086
+ return {
56087
+ running: useDeviceState(props.trpc, props.deviceId, (s) => s.runningState),
56088
+ power: useDeviceState(props.trpc, props.deviceId, (s) => s.powerMeter)
55653
56089
  };
55654
- return /* @__PURE__ */ jsxs("div", {
55655
- ref: trackRef,
55656
- role: "slider",
55657
- "aria-label": label,
55658
- "aria-valuemin": min,
55659
- "aria-valuemax": max,
55660
- "aria-valuenow": shown,
55661
- "aria-disabled": disabled,
55662
- tabIndex: disabled ? -1 : 0,
55663
- onPointerDown,
55664
- onPointerMove,
55665
- onPointerUp: endDrag,
55666
- onPointerCancel: endDrag,
55667
- onKeyDown,
55668
- className: cn("mt-1 w-full touch-none select-none py-2", disabled ? "cursor-not-allowed opacity-40" : "cursor-ew-resize"),
55669
- children: [/* @__PURE__ */ jsxs("div", {
55670
- className: "relative h-1.5 w-full rounded-full bg-surface-subtle",
55671
- children: [/* @__PURE__ */ jsx("div", {
55672
- className: "absolute inset-y-0 left-0 rounded-full",
55673
- style: {
55674
- width: pct,
55675
- background: accent
55676
- }
55677
- }), /* @__PURE__ */ jsx("div", {
55678
- className: "absolute top-1/2 h-3.5 w-3.5 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-surface shadow",
55679
- style: {
55680
- left: pct,
55681
- background: accent
55682
- }
55683
- })]
55684
- }), /* @__PURE__ */ jsxs("div", {
55685
- className: "mt-0.5 flex justify-between text-[9px] tabular-nums text-foreground-subtle",
55686
- children: [/* @__PURE__ */ jsxs("span", { children: [min, "°"] }), /* @__PURE__ */ jsxs("span", { children: [max, "°"] })]
55687
- })]
55688
- });
55689
56090
  }
55690
- /**
55691
- * Animated centerpiece. `fan_only` renders a spinning fan; `off` a dim static
55692
- * vent; every active mode renders drifting particles that FALL (cool/dry/auto)
55693
- * or RISE (heat), with a horizontal sweep overlaid when a swing axis is active.
55694
- */
55695
- function AirflowViz({ mode, accent, periodSec, swaying, forceRising = false }) {
55696
- const columns = [
55697
- 0,
55698
- 1,
55699
- 2,
55700
- 3,
55701
- 4,
55702
- 5
55703
- ];
55704
- const rising = forceRising || mode === "heat";
55705
- const isDroplet = mode === "dry";
56091
+ /** The drum: a ring with a few items in it, turning only while a cycle runs. */
56092
+ function Drum({ running }) {
55706
56093
  return /* @__PURE__ */ jsx("div", {
55707
- "aria-hidden": true,
55708
- className: "absolute inset-0 overflow-hidden",
55709
- children: mode === "off" ? /* @__PURE__ */ jsx("div", {
55710
- className: "flex h-full items-center justify-center gap-2 opacity-30",
55711
- children: columns.map((i) => /* @__PURE__ */ jsx("span", { className: "h-8 w-1 rounded-full bg-foreground-subtle opacity-40" }, i))
55712
- }) : mode === "fan_only" ? /* @__PURE__ */ jsx("div", {
55713
- className: "flex h-full items-center justify-center",
55714
- children: /* @__PURE__ */ jsx(FanBlades, {
55715
- color: accent,
55716
- periodSec: Math.max(.5, periodSec * .7),
55717
- size: 56
55718
- })
55719
- }) : /* @__PURE__ */ jsx("div", {
55720
- "data-testid": forceRising ? "climate-heat-rise" : void 0,
55721
- className: cn("acv-sway-wrap absolute inset-0", swaying && "acv-sway"),
55722
- style: swaying ? { animation: "acv-sway 2.6s ease-in-out infinite" } : void 0,
55723
- children: columns.map((i) => {
55724
- return /* @__PURE__ */ jsx("span", {
55725
- className: "acv-streak absolute rounded-full",
55726
- style: {
55727
- left: `${8 + i * 15}%`,
55728
- width: isDroplet ? "0.4rem" : "0.3rem",
55729
- height: isDroplet ? "0.4rem" : "1.9rem",
55730
- background: accent,
55731
- boxShadow: `0 0 6px ${accent}`,
55732
- animationName: rising ? "acv-rise" : "acv-fall",
55733
- animationTimingFunction: "linear",
55734
- animationIterationCount: "infinite",
55735
- animationDuration: `${periodSec}s`,
55736
- animationDelay: `${i % 3 * (periodSec / 3) + i * .05}s`
55737
- }
55738
- }, i);
55739
- })
56094
+ "aria-hidden": "true",
56095
+ "data-testid": "appliance-drum",
56096
+ "data-running": running === true ? "running" : running === false ? "idle" : "unknown",
56097
+ className: "relative flex h-28 w-28 shrink-0 items-center justify-center rounded-full border-2 border-border bg-surface-hover",
56098
+ children: /* @__PURE__ */ jsxs("div", {
56099
+ className: cn("relative h-20 w-20 rounded-full border-2", running === true ? "apl-drum-run border-primary" : "border-border"),
56100
+ "data-testid": "appliance-drum-ring",
56101
+ children: [
56102
+ /* @__PURE__ */ jsx("span", { className: "absolute left-2 top-4 h-3 w-3 rounded-full bg-primary/40" }),
56103
+ /* @__PURE__ */ jsx("span", { className: "absolute bottom-3 right-3 h-4 w-4 rounded-full bg-info/40" }),
56104
+ /* @__PURE__ */ jsx("span", { className: "absolute bottom-4 left-4 h-2.5 w-2.5 rounded-full bg-foreground-subtle/40" })
56105
+ ]
55740
56106
  })
55741
56107
  });
55742
56108
  }
55743
- /** Still radiator fins — the off state of a heating-only climate. */
55744
- function RadiatorFins() {
55745
- return /* @__PURE__ */ jsx("div", {
55746
- "data-testid": "climate-radiator",
55747
- "aria-hidden": true,
55748
- className: "flex h-full items-end justify-center gap-1.5 px-8 pb-3 opacity-40",
56109
+ function ApplianceHeroCard(props) {
56110
+ const t = useUiText();
56111
+ const { running, power } = useApplianceState(props);
56112
+ const state = running?.running ?? null;
56113
+ const meta = applianceStateLabel(state, t);
56114
+ const phase = running?.phase?.trim() ?? "";
56115
+ const dwell = running === void 0 ? null : dwellText(state, running.since, Date.now(), t);
56116
+ return /* @__PURE__ */ jsxs("div", {
56117
+ className: "flex items-center gap-4 rounded-lg border border-border bg-surface p-4",
55749
56118
  children: [
55750
- 0,
55751
- 1,
55752
- 2,
55753
- 3,
55754
- 4,
55755
- 5,
55756
- 6
55757
- ].map((i) => /* @__PURE__ */ jsx("span", { className: "h-10 w-1.5 rounded-t-full bg-foreground-subtle" }, i))
56119
+ /* @__PURE__ */ jsx("style", { children: KEYFRAMES }),
56120
+ /* @__PURE__ */ jsx(Drum, { running: state }),
56121
+ /* @__PURE__ */ jsxs("div", {
56122
+ className: "flex min-w-0 flex-1 flex-col gap-2",
56123
+ children: [
56124
+ /* @__PURE__ */ jsxs("div", {
56125
+ className: "flex flex-wrap items-baseline gap-x-2",
56126
+ children: [/* @__PURE__ */ jsx("span", {
56127
+ "data-testid": "appliance-state",
56128
+ className: cn("text-3xl font-semibold", meta.tone),
56129
+ children: meta.label
56130
+ }), dwell !== null && /* @__PURE__ */ jsx("span", {
56131
+ className: "text-sm tabular-nums text-foreground-subtle",
56132
+ children: dwell
56133
+ })]
56134
+ }),
56135
+ phase !== "" && state !== null && /* @__PURE__ */ jsx("span", {
56136
+ className: "text-sm text-foreground-subtle",
56137
+ children: phase
56138
+ }),
56139
+ power !== void 0 && /* @__PURE__ */ jsxs("span", {
56140
+ "data-testid": "appliance-power",
56141
+ className: "inline-flex items-center gap-1 text-sm tabular-nums text-foreground-muted",
56142
+ title: power.power === void 0 ? t("uiLibrary.appliance.powerUnknown", "Power unknown") : void 0,
56143
+ children: [/* @__PURE__ */ jsx(Zap, {
56144
+ className: "h-3.5 w-3.5",
56145
+ "aria-hidden": true
56146
+ }), formatWatts(power.power)]
56147
+ })
56148
+ ]
56149
+ })
56150
+ ]
55758
56151
  });
55759
56152
  }
55760
- /** Big spinning fan for `fan_only` mode. */
55761
- function FanBlades({ color, periodSec, size }) {
55762
- return /* @__PURE__ */ jsxs("svg", {
55763
- width: size,
55764
- height: size,
55765
- viewBox: "0 0 100 100",
55766
- className: "acv-fan",
55767
- style: {
55768
- animation: `acv-spin ${periodSec}s linear infinite`,
55769
- transformOrigin: "50% 50%"
55770
- },
55771
- "aria-hidden": true,
55772
- children: [[
55773
- 0,
55774
- 120,
55775
- 240
55776
- ].map((deg) => /* @__PURE__ */ jsx("path", {
55777
- d: "M50 50 C 58 30, 78 26, 84 12 C 66 20, 54 34, 50 50 Z",
55778
- fill: color,
55779
- opacity: .85,
55780
- transform: `rotate(${deg} 50 50)`
55781
- }, deg)), /* @__PURE__ */ jsx("circle", {
55782
- cx: "50",
55783
- cy: "50",
55784
- r: "7",
55785
- fill: color
56153
+ function ApplianceInlineControl(props) {
56154
+ const { running, power } = useApplianceState(props);
56155
+ return /* @__PURE__ */ jsxs("div", {
56156
+ className: "inline-flex items-center gap-1.5 max-w-full",
56157
+ children: [/* @__PURE__ */ jsx(RunningBadge, {
56158
+ running: running?.running ?? null,
56159
+ children: /* @__PURE__ */ jsx(WashingMachine, {
56160
+ className: "h-4 w-4 text-foreground-muted",
56161
+ "aria-hidden": true
56162
+ })
56163
+ }), power !== void 0 && /* @__PURE__ */ jsx("span", {
56164
+ className: "text-xs tabular-nums text-foreground-subtle",
56165
+ children: formatWatts(power.power)
55786
56166
  })]
55787
56167
  });
55788
56168
  }
55789
- /** Swing axis toggle — a card with a MoveVertical/Horizontal glyph that
55790
- * oscillates along its axis when on. On/off is non-destructive → plain tap. */
55791
- function SwingToggle({ axis, on, busy, onToggle }) {
56169
+ //#endregion
56170
+ //#region src/composites/device-controls/heating-valve-readout.tsx
56171
+ function formatHeatingValvePosition(position) {
56172
+ return position !== null ? `${position}%` : "—";
56173
+ }
56174
+ function HeatingValveReadout({ trpc, deviceId, layout }) {
55792
56175
  const t = useUiText();
55793
- const label = axis === "vertical" ? t("uiLibrary.acPanel.vertical", "Vertical") : t("uiLibrary.acPanel.horizontal", "Horizontal");
55794
- const Icon = axis === "vertical" ? MoveVertical : MoveHorizontal;
55795
- const anim = axis === "vertical" ? "acv-swing-v" : "acv-swing-h";
55796
- return /* @__PURE__ */ jsxs("button", {
55797
- type: "button",
55798
- "aria-label": t("uiLibrary.acPanel.swingAxis", "{{axis}} swing", { axis: label }),
55799
- "aria-pressed": on,
55800
- disabled: busy,
55801
- onClick: () => {
55802
- if (!busy) onToggle(!on);
55803
- },
55804
- className: cn("flex items-center justify-center gap-2 rounded-lg border px-2 py-1.5 text-xs font-medium transition-colors", on ? "border-transparent bg-indigo-400 text-indigo-950 shadow-sm" : "border-border/60 bg-surface-subtle text-foreground-subtle hover:bg-surface-hover hover:text-foreground", busy && "opacity-40 cursor-not-allowed"),
55805
- children: [/* @__PURE__ */ jsx(Icon, {
55806
- className: "acv-swing h-4 w-4",
55807
- "aria-hidden": true,
55808
- style: on ? { animation: `${anim} 1.4s ease-in-out infinite` } : void 0
55809
- }), label]
56176
+ const { cap, slice } = useDeviceCapability({
56177
+ trpc,
56178
+ deviceId,
56179
+ cap: (d) => d.heatingValve,
56180
+ slice: (d) => d.state.heatingValve
56181
+ });
56182
+ if (cap === void 0 || slice === void 0) return null;
56183
+ const label = t("uiLibrary.heatingValveReadout.valve", "Valve");
56184
+ const value = formatHeatingValvePosition(slice.position);
56185
+ if (layout === "compact") return /* @__PURE__ */ jsx("span", {
56186
+ className: "inline-flex items-center text-xs tabular-nums text-foreground-subtle",
56187
+ "aria-label": `${label} ${value}`,
56188
+ children: value
56189
+ });
56190
+ return /* @__PURE__ */ jsxs("div", {
56191
+ className: "flex items-center gap-2 text-xs tabular-nums text-foreground-subtle",
56192
+ children: [/* @__PURE__ */ jsx("span", { children: label }), /* @__PURE__ */ jsx("span", {
56193
+ className: "font-medium text-foreground",
56194
+ children: value
56195
+ })]
55810
56196
  });
55811
56197
  }
55812
56198
  //#endregion
@@ -57898,6 +58284,10 @@ var CONTROL_KIND_COMPONENTS = {
57898
58284
  InlineControl: PetFountainInlineControl,
57899
58285
  HeroCard: PetFountainHeroCard
57900
58286
  },
58287
+ heater: {
58288
+ InlineControl: HeaterInlineControl,
58289
+ HeroCard: HeaterHeroCard
58290
+ },
57901
58291
  dishwasher: {
57902
58292
  InlineControl: DishwasherInlineControl,
57903
58293
  HeroCard: DishwasherHeroCard
@@ -57985,6 +58375,7 @@ var CONTROL_FILLS = {
57985
58375
  [DeviceType.Image]: false,
57986
58376
  [DeviceType.PetFeeder]: false,
57987
58377
  [DeviceType.PetFountain]: false,
58378
+ [DeviceType.Heater]: false,
57988
58379
  [DeviceType.Dishwasher]: false,
57989
58380
  [DeviceType.Washer]: false,
57990
58381
  [DeviceType.Dryer]: false
@@ -72457,6 +72848,9 @@ function TimelineSlider({ markers, bands = [], selectedId = null, step = 5, aria
72457
72848
  });
72458
72849
  }
72459
72850
  //#endregion
72851
+ //#region src/ui-library-version.ts
72852
+ var uiLibraryVersion = "1.2.370";
72853
+ //#endregion
72460
72854
  //#region src/hooks/use-account-unit-preferences.ts
72461
72855
  /**
72462
72856
  * Unit preferences in the signed-in user's ACCOUNT preferences (D894): one
@@ -73399,12 +73793,12 @@ var statusIcons = {
73399
73793
  * Render inside `<Suspense>` at all call sites. */
73400
73794
  var MaskShapeCanvas = lazy(() => import("./MaskShapeCanvas-C9cJlxvG.js").then((m) => ({ default: m.MaskShapeCanvas })));
73401
73795
  /** Lazy-wrapped `MotionZonesSettings` — code-split off the main bundle. */
73402
- var MotionZonesSettings = lazy(() => import("./MotionZonesSettings-dx3wObgK.js").then((m) => ({ default: m.MotionZonesSettings })));
73796
+ var MotionZonesSettings = lazy(() => import("./MotionZonesSettings-Zcfa5c9l.js").then((m) => ({ default: m.MotionZonesSettings })));
73403
73797
  /** Lazy-wrapped `SceneMonitorEditor` — code-split off the main bundle for the
73404
73798
  * same reason: it mounts `MaskShapeCanvas`, which chains react-konva. Render
73405
73799
  * inside `<Suspense>`; the admin-ui `/scenes` dialog is its only caller. */
73406
- var SceneMonitorEditor = lazy(() => import("./SceneMonitorEditor-CI72S4eN.js").then((m) => ({ default: m.SceneMonitorEditor })));
73800
+ var SceneMonitorEditor = lazy(() => import("./SceneMonitorEditor-C8YXVzYI.js").then((m) => ({ default: m.SceneMonitorEditor })));
73407
73801
  /** Lazy-wrapped `PrivacyMaskSettings` — code-split off the main bundle. */
73408
- var PrivacyMaskSettings = lazy(() => import("./PrivacyMaskSettings-BM2C_xWz.js").then((m) => ({ default: m.PrivacyMaskSettings })));
73802
+ var PrivacyMaskSettings = lazy(() => import("./PrivacyMaskSettings-B_X42yzN.js").then((m) => ({ default: m.PrivacyMaskSettings })));
73409
73803
  //#endregion
73410
- export { Shield as $, CloudRain as $n, LockOpen as $t, Trash2 as A, AddProviderEntryDialog, AddonGlobalSettingsForm, AdminLinkQuickAction, AgentStepEditor, AlarmHeroCard, AlarmInlineControl as AlarmPanelInlineControl, Flame as An, AppShell, Bone as Ar, ArcKnob, Pencil as At, AudioClassificationList, AudioLevelWaveform, AudioWaveform, AutomationHeroCard, AutomationInlineControl, AutotrackSection, Sun as B, BATTERY_BADGE_LOW_KEY, BATTERY_BADGE_NORMAL_KEY, BINARY_BATTERY_LOW_BELOW, BOOLEAN_STATES, BTN_COMPACT, BTN_COMPACT_DANGER, BTN_COMPACT_PRIMARY, BTN_COMPACT_WARNING, BackToStepsButton, Badge, BarSeries, BatteryBadge, Droplet as Bn, BottomSheet, BatteryFull as Br, Breadcrumb, BrightnessPanel, BrokerPickerSlotProvider, MousePointerClick as Bt, Button, ButtonControl, ButtonHeroCard, Unlink2 as C, CENTER, CHART_SERIES_TOKENS, CHIP_ACTIVE, CHIP_BASE, CHIP_INACTIVE, CLASS_COLORS, COLUMN_BREAKPOINT_CLASS, COLUMN_PRIORITY, COMMIT_DEDUPE_TOLERANCE_MS, COMMIT_DEDUPE_WINDOW_MS, CONSUMABLE_LOW_PERCENT, CONTROL_CAP_NAMES, CONTROL_FILLS, CameraStreamPlayer, Card, ChartFrame, ChartPlaceholder, ChartSwatch, ChartWindowToggle, Checkbox, ChildSectionAccordion, ClimatePanel, GraduationCap as Cn, CodeBlock, CollapsibleCard, ConfigFormBuilder, FormField as ConfigFormField, ConfigNotificationTargetMultiSelectFieldView, ConfigNotificationTargetSelectFieldView, ConfigSchemaField, ConfirmActionButton, ConfirmDialogProvider, ConsumableLevelBadge, ConsumablesPanel, ContainerChildrenProvider, ContainerPrimaryHero, ControlColumn, ControlHeroCard, ControlInlineControl, ControlPanel, CopyButton, CoverHeroCard, CoverInlineControl, CoverPanel, Car as Cr, Plug as Ct, CustomFieldRenderersProvider, TriangleAlert as D, DATA_RECORDS_KIND_PARAM, DATA_RECORDS_OWNER_PARAM, DATA_RECORD_FACET_GROUPS, DEFAULT_COLOR, DEFAULT_PAGINATION_LABELS, DEFAULT_UNIT_PREFERENCES, DEVICE_COLUMNS, DEVICE_EXPORT_PAGE_SIZE_KEY, DEVICE_LIST_PAGE_SIZE_KEY, DEVICE_LIST_PAGE_SIZE_OPTIONS, DEVICE_NAME_FORMS, DEVICE_NAME_JOIN, DEVICE_PICKER_GROUP_STORAGE_KEY, DEVICE_ROLE_META, DEVICE_ROLE_NOUNS, DEVICE_TYPE_CONTROL, DEVICE_TYPE_META, DEVICE_TYPE_NOUNS, DataRecordsHub, DataTable, DataTableFilterBar, DataTablePager, DetectionCanvas, DetectionOverlay, DetectionResultTree, DevShell, DeviceActivityPanel, DeviceBatchToolbar, DeviceCard, DeviceContextProvider, DeviceExportPanel, DeviceExportSetup, DeviceFilterBar, DeviceFleetFromServer, DeviceFleetProvider, DeviceGrid, DeviceHistoryView, DeviceItem, DeviceList, DeviceMultiSelectField, DeviceName, DevicePicker, DeviceQuickDetailProvider, DeviceSelectField, DeviceSelectorPicker, DeviceStepMatrix, DevicesFailedLine, DevicesLoadingLine, DevicesWidenWarning, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DisclosureChevron, DiscoveryPanel, DisplayPaletteProvider, Footprints as Dn, DoorbellRecentPanel, Bug as Dr, Dropdown, DropdownContent, DropdownItem, DropdownTrigger, Pipette as Dt, DummyHeroCard, DummyInline, Truck as E, EMPTY_DATA_TABLE_FILTER, EMPTY_HISTORY_PANELS, EVENT_KIND_ICONS, EmptyState, Funnel as En, EndpointResultsCard, EndpointTestCard, EntryJsonSchemaForm, Bus as Er, ErrorBox, Plane as Et, EventKindGlyph, EventStream, ExtensionsPanel, Timer as F, FALLBACK_SCOPE, FAST_ICON_GLYPHS, FILL, FLEET_LIST_GC_TIME_MS, FLEET_LIST_QUERY_KEY, FLEET_LIST_STALE_TIME_MS, FanHeroCard, FanInlineControl, FanPanel, FileInput, FilterBar, FloatingEventStream, FloatingLogStream, FloatingPanel, EyeOff as Fn, FormField$1 as FormField, BellRing as Fr, Navigation as Ft, Sparkles as G, GAP_INTERVAL_FACTOR, GRID_GAP, GRID_PAIRED, GRID_QUICK_STATS, GateBadge, GateControl, Database as Gn, ArrowUpToLine as Gr, GripTrack, GroupedModelSelector, GroupedTilePicker, Mic as Gt, Star as H, HISTORY_PAGE_PATH, HISTORY_PANELS_NAMESPACE, HISTORY_SELECTION_MAX, HISTORY_WINDOW_IDS, HISTORY_WINDOW_MS, HOST_WIDGETS, HUB_SESSION_RUN_MS, HistoryChart, HistoryWindowBar, HlsVideo, DoorOpen as Hn, HotkeyProvider, HotkeyScope, HoverZoomImage, Ban as Hr, MonitorPlay as Ht, HubSessionTestCard, HumidifierHeroCard, HumidifierInlineControl, Thermometer as I, INPUT_COMPACT, INPUT_SHELL, IconAction, IconButton, IconPicker, ImageHeroCard, ImageInlineControl, ImageSelector, ExternalLink as In, InferenceConfigSelector, Input, Battery as Ir, Music as It, ItemFormDialog, SlidersHorizontal as J, Copy as Jn, ArrowDown as Jr, Megaphone as Jt, Snowflake as K, KebabMenu, KeyValueList, Crosshair as Kn, ArrowRight as Kr, MessageSquare as Kt, Target as L, LIST_ROW, Label, LawnMowerHeroCard, LawnMowerInlineControl, LayeredSettingsForm, LightHeroCard, LightInlineControl, Eraser as Ln, LockHeroCard, LockInlineControl, LockPanel, LogStream, LoginForm, BatteryWarning as Lr, Move as Lt, Tractor as M, MEDIA_GRID, MINUTES_PER_DAY, MODE_COLOR, MaskShapeCanvas, MediaCard, MediaGrid, MediaPlayerHeroCard, MediaPlayerInlineControl, MediaPlayerPanel, Feather as Mn, MobileDrawer, ModelPicker, MotionZonesSettings, Bird as Mr, Pause as Mt, ToggleRight as N, NAVIGATION_DRIVE_INTERVAL_MS, NODE_COLOR_IDS, NatResultCard, NavigationPanel, NetworkLinkBadge, Fan as Nn, NodeMultiSelectField, NodePicker, NodeSelectField, NotificationTargetSelectField, NotificationTargetsField, Bike as Nr, Package as Nt, TrendingDown as O, OCCUPANCY_KEY, OPTION_SELECT_SEARCH_MIN_OPTIONS, OfflineBadge, Flashlight as On, OptionSelect, Box as Or, Pin as Ot, ToggleLeft as P, PAGE_SIZE_ALL, PHASE_CONFIG, PICKER_CHIP_LIMIT, PICKER_DEFAULT_GROUP_BY, PICKER_GROUP_BY_MODES, PICKER_GROUP_COLLAPSE_AT, PICKER_NONE_KEY, PICKER_NOUN_PLURAL, PICKER_NO_FILTERS, PICKER_PAGE_SIZE, PICKER_SEARCH_DEBOUNCE_MS, PICKER_WINDOW, PRIORITY, PTZOverlay, PageHeader, PageShell, PageSizeSelect, Pagination, PasswordInput, PhaseIcon, PipelineBuilder, PipelineRuntimeSelector, PipelineStep, PlaceholderChipField, PlayerOverlaysProvider, Eye as Pn, Popover, PopoverContent, PopoverRowAction, PopoverTrigger, Bell as Pr, PrimaryChildPicker, PrivacyMaskSettings, ProviderBadge, ProviderEntryPills, Network as Pt, PtzPanel, Ship as Q, CloudSnow as Qn, Activity as Qr, QrCode, Lock as Qt, QuantityValueInput, Tag as R, RECONNECT_POLICY, RECORDED_PLAYBACK_MODES, RESOLUTION_BUCKET_MS, RIGHT, ROI_AREA_WARN_FRACTION, ROLE_DESCRIPTOR, ROOT_DETECTOR_STEP_ID, RadialGauge, Radio, RecordEntriesPanel, RecordedPlaybackProvider, RecordingPanel, ResponseLog, RetrainReviewBadge, EllipsisVertical as Rn, RoleDisplayDefaultsFromServer, RoleDisplayDefaultsProvider, RoleNodePill, RootModelSourceControl, RootSuppliedModelNote, BatteryMedium as Rr, MoveVertical as Rt, RunReport, RunningBadge, RunningStatusLine, Upload as S, SCENE_CAPTURE_VARIANTS, SECRET_MASK_PLACEHOLDER, SECRET_REVEAL_MS, SECTION_BODY, SECTION_CARD, SECTION_HEADER, SETTING_ROW, SETTING_ROW_LABEL, SETTING_ROW_STACK_BREAKPOINT, SETTING_ROW_VALUE, SETTING_ROW_VALUE_TEXT, SNAPSHOT_MEDIA_PATH, SPLIT_PANEL_OUTER, SPLIT_PANEL_SIDE, STACK_GAP, STATE_COLOR, STEP_DOCK_WIDTH_PX, SUBJECT_PATH_DWELL_EPS, SUBJECT_PATH_FULL_FRAME_COVERAGE, SUBJECT_PATH_MAX_POINTS, SceneMonitorEditor, ScopePicker, ScriptHeroCard, ScriptInlineControl, ScrollArea, SecretFieldControl, SecretRevealProvider, SectionCard, SectionToolbar, SectionedPage, SegmentedChoice, Select, SelectedChip, SemanticBadge, SendFrameToTrainingButton, SensorHeroCard, SensorInlineControl, SensorValueAtom, Separator, SettingRow, Sidebar, SidebarItem, Skeleton, SlideToggle, Slider, Grid2x2 as Sn, SnapshotButton, SortHeaderButton, Sparkline, Cast as Sr, PowerOff as St, StableTabPanel, StatCard, StateTimeline, StateValuesStream, StatusBadge, StepDetailDock, StepInspectorPanel, StepModelRow, StepTimings, Stepper, StorageRecordsPanel, StreamBrokerSelector, StreamDebugOverlay, StreamPanel, Switch, SwitchHeroCard, SwitchInlineControl, SwitchPanel, SystemProvider, Type as T, TABLE_SCROLL_MAX_H, TEMPERATURE_SCALES, TEXT_FIELD_LABEL, TEXT_HINT, TEXT_METRIC, TEXT_SECTION_LABEL, TEXT_VALUE, TIMEZONES, Tabs, TabsContent, TabsList, TabsTrigger, TapToggle, Textarea, ThemeProvider, ThermostatHeroCard, ThermostatInlineControl, TimeSeriesChart, TimelineSlider, TimezoneSelector, Gamepad2 as Tn, Tooltip, TooltipContent, TooltipTrigger, Cable as Tr, TrainingBaseModelPicker, TrainingCollectionPicker, Play as Tt, Square as U, UNIT_PREFERENCES_NAMESPACE, UiTextProvider, UiTrans, DoorClosed as Un, UnitPicker, UnitPreferencesFromServer, UnitPreferencesProvider, Baby as Ur, Minus as Ut, SunMedium as V, VacuumHeroCard, VacuumInlineControl, ValueReadout, ValveHeroCard, ValveInlineControl, VersionBadge, ViewSwitch, Download as Vn, VodPlaybackProvider, Bath as Vr, Moon as Vt, Sprout as W, WaterHeaterHeroCard, WaterHeaterInlineControl, WeatherHeroCard, WeatherInlineControl, WidgetMetricCard, WidgetPanel, WidgetRegistryProvider, WidgetSlot, Dog as Wn, ArrowUp as Wr, Minimize2 as Wt, SkipBack as X, Cloud as Xn, AlarmSmoke as Xr, MapPin as Xt, SkipForward as Y, Cog as Yn, ArrowDownToLine as Yr, Maximize2 as Yt, Siren as Z, CloudSun as Zn, ZoneEditingProvider, AirVent as Zr, Mail as Zt, Vibrate as _, Hash as _n, ChevronLeft as _r, RadioTower as _t, Wrench as a, acceleratorLabel, acceleratorShortLabel, agentColumnKey, alignSeries, allDeviceTypeFilterOptions, Lightbulb as an, anchorNow, applyFleetQueryDefaults, applyPickerFilters, CircleStop as ar, ariaSortForColumn, assignNodeColorId, Server as at, axisTicks, User as b, badgeFor, binaryBatteryIsLow, bindsToModel, Hammer as bn, booleanLabels, boundsInPicked, ChartLine as br, Puzzle as bt, bucketTotals, buildColorByNodeId, buildDataRecordRows, buildPeerConnectionConfig, buildStepTreeFromSchema, buildSubjectPath, buildTimeSeriesModel, Wifi as c, catalogHasDraft, chartKeys, chartSeriesStyle, childEntityId, childListName, chipOverflow, chunk, clampMinute, classifyAddressScope, classifyCapability, classifySessionVerdict, clearPickerGroup, clusterRootModelIds, cn, colorIdForNode, columnsForContext, compareSrflxMappings, computePageButtons, consumableItemLevel, consumableLevelBarClass, consumableLevelLabel, consumableLevelVariant, containerChildToRef, countableDevices, coverHighlight, coverageLine, CirclePause as cr, createAddonI18n, createSharedContext, createTheme, Scan as ct, currentAddonLanguage, cursorFractionFor, WifiLow as d, darkColors, dataRecordContents, dataRecordKey, dataRecordSearchText, dataRecordType, dataTableFacetGroups, dataTableFacets, decodeCustomWindow, decodeSeriesRef, defaultAxisSpec, defaultOfField, defaultSelectClusterRoots, defaultSingleClusterRoot, defaultTheme, defaultUiText, deriveDeviceKind, deriveWebrtcDebugStats, describeDeviceSelector, detectPlatform, deviceIntegrationResolver, deviceListStateOf, deviceMatchesFilter, deviceNameNouns, deviceOptionLabel, deviceRoleMeta, deviceRoleMetaOf, deviceTypeLabel, deviceTypeMeta, deviceTypeMetaOf, devicesToOptions, Inbox as dn, dockBox, CircleCheckBig as dr, draftFromQuery, Router as dt, effectivePageSize, emptyDevicesWidens, emptySessionRun, LocateFixed as en, encodeCustomWindow, encodeSeriesRef, energyBuckets, ensureMfHostInit, CloudLightning as er, ShieldOff as et, eventKindLabel, WifiHigh as f, filterDataTableRows, filterDeviceOptions, filterOccupancyLines, filterOptions as filterOptionSelectOptions, filterPickerDevices, finalizeSessionRun, findTimezone, flattenPickerGrouping, flattenPickerRows, fleetViewOf, Image as fn, foldDeviceName, formatChartBytes, formatChartNumber, formatChartValue, formatControlDateTime, formatDeviceName, formatLastSeen, formatNumeric, formatSettingValue, formatSpan, formatTimeLabel, CircleAlert as fr, freezeVerdict, Route as ft, fuzzyMatch, Volume2 as g, gapThresholdMs, getClassColor, getPhaseVisual, Heater as gn, ChevronRight as gr, groupAgentColumns, groupChildrenByLayout, groupDeviceSeries, groupPickerDevices, groupPickerDevicesBy, Radio$1 as gt, VolumeX as h, hardwareLabel, historyPageHref, History as hn, ChevronUp as hr, RefreshCw as ht, hubOrigin, hubPath, hubUrl, hubWsUrl, humanDuration, humanizeName, humidifierTint, X as i, iconGlyphsFailed, iconGlyphsLoaded, Link2 as in, indexDeviceNames, initialScrubState, insertAtSelection, CircleX as ir, isAbsentProvider, isByteUnit, isConsumableLevelField, isDataTableFilterActive, isDeviceNameStock, isDrawableSubjectPath, isFieldVisible, isGroupExpanded, isHistoryWindowId, isKeychainFieldValue, isModelScopedField, isPickableUnit, isRedactedSecret, isRefusal, isSecretField, isValueField, Settings as it, TrainFront as j, Film as jn, Blinds as jr, PawPrint as jt, TrendingUp as k, FlashlightOff as kn, Bot as kr, Phone as kt, WifiZero as l, lawnMowerActivityMeta, lightColors, linePoints, Laugh as ln, loadIconGlyphs, loadRemoteBundle, CircleDot as lr, Save as lt, lucideExportName, WashingMachine as m, makeScrubBridge, mapRootDetectorPlacements, matchesCombo, mergeSecretForSubmit, metadataEntries, metadataString, minuteFromPointer, House as mn, mountAddonPage, mountPath, ChevronsDownUp as mr, RotateCcw as mt, ZoomIn as n, nextGridPosition, nextReconnectAction, nextSort, nextSortDirection, nextTableSort, niceMax, niceRange, List as nn, nodeColorClass, nodeSoftBgClass, nodeTextColorClass, normalizeForSearch, normalizeLanguage, normalizeSelection, nounSpecFor, Clock as nr, ShieldAlert as nt, Workflow as o, occupancyFacets, occupancyLines, offListSelections, Leaf as on, openTopLayer, optionSearchText as optionSelectSearchText, CircleQuestionMark as or, orphanDeviceLabel, Search as ot, outsideBounds, overrideEntityIdFromLink, Waves as p, pageRows, pageSizeLabel, paginateRows, parentDetailOf, parseCapKey, parseCombo, parseConsumableLevel, parseIceCandidate, parsePickerGroupBy, parseProducerKey, parseRecordedServerMessage, partitionSelected as partitionOptionSelectSelected, partitionSuggested, pickerFacetFilterShown, pickerFacetKey, pickerFacetOptions, pickerFiltersActive, pickerGroupKey, pickerHiddenSelectedCount, pickerLocationKey, pickerQueryTokens, pickerRowFacts, pickerSearchText, pickerZoneFilterSuspended, pinnedStreamChoices, placePopover, ImageOff as pn, ChevronsUpDown as pr, preferenceForQuantity, previousWindow, projectSubjectPath, providerIcons, RotateCw as pt, Smartphone as q, Cpu as qn, ArrowLeft as qr, Menu as qt, quantityStoredUnit, quantityUnitChoices, Zap as r, readHistory, readHistoryPanels, readItemId, readStoredGroupBy, readUnitPreferences, reduceSessionRun, registerAddonBundle, renderMarkup, renderTagged, resetHubMountForTests, resetPickerFilters, resolveContainerPrimary, resolveControlAlign, resolveDeviceControl, resolveDeviceIntegration, resolveDeviceLabel, resolveDisplayIcon, resolveEffectiveDefaultModel, resolveEffectiveStepModel, resolveEventKindIcon, resolveHistoryWindow, resolveSearchable as resolveOptionSelectSearchable, resolveParentNames, resolvePrimaryChild, resolveSelectedDevices, resolveSensorDisplay, resolveStepDefaultModel, retrainReviewBadgeLook, ListChecks as rn, roiTooLarge, rootSourceState, routerBasename, Clapperboard as rr, Share2 as rt, runningDurationSince, runningStatusParts, Wind as s, sameDeviceName, sameLocationSuggestions, scrubReducer, searchSteps, secretDisplayValue, secretSubmitValue, segmentsFromChanges, selectPickerGroup, selectedDeviceOptions, serializeRecordedCommand, seriesRefId, settingsModelIdFor, sharedGapSpans, shiftPoints, shouldCommit, shouldEmit, shouldShowAddNewFooter, shouldShowUseQueryRow, shouldUseSingleNode, showsNoCamerasHint, LayoutGrid as sn, snapMinute, sortRows, sortRowsByColumn, CirclePlus as sr, ScrollText as st, stackBuckets, stackSeries, stateAt, stateRow, stateStyle, statusIcons, statusLine, stepFieldDomId, stepHasModelForFormat, stepLocalFields, stepModelOptions, storedToPicked, stripDeviceParentPrefix, stripParentNamePrefix, subjectPathSampleFromBox, subjectPathSvgPoints, summarizeHubCandidates, swatchFillClass, swatchLineClass, ZoomOut as t, tabForSelector, themeToCss, themeToRootCss, timeInState, LoaderCircle as tn, toStationaryOverlayBox, toggleDataTableFacet, toggleDataTableGroupFacet, togglePickerDevice, togglePickerKey, CloudFog as tr, trainingRefusalText, translateAddonKey, trpc, ShieldCheck as tt, typeLabel, typedToStored, WifiOff as u, Info as un, unitAxes, CircleCheck as ur, useAccessoriesGetStatus, useAccessoriesSetChildHidden, useAccountUnitPreferences, useActionSourceListActions, useActionSourceRunAction, useActionSourceStopAction, useActionsCreate, useActionsDelete, useActionsGet, useActionsGetLinks, useActionsGetTraces, useActionsList, useActionsListForCamera, useActionsRun, useActionsSetLinks, useActionsStop, useActionsUpdate, useAddonPagesListPages, useAddonSettingsGetDeclaredSettingsKeys, useAddonSettingsGetDeviceSettings, useAddonSettingsGetGlobalSettings, useAddonSettingsGetIntegrationFormSchema, useAddonSettingsGetIntegrationSettings, useAddonSettingsUnsetStoredSettingsKeys, useAddonSettingsUpdateDeviceSettings, useAddonSettingsUpdateGlobalSettings, useAddonT, useAddonWidgetsListWidgets, useAddonsApplyAutoUpdateToAll, useAddonsCancelJob, useAddonsCustom, useAddonsForceRefresh, useAddonsGetAddonAutoUpdate, useAddonsGetAutoUpdateSettings, useAddonsGetJob, useAddonsGetLastRestart, useAddonsGetLogs, useAddonsGetPackageDocs, useAddonsGetVersions, useAddonsInstallPackage, useAddonsList, useAddonsListCapabilityProviders, useAddonsListFrameworkPackages, useAddonsListInstallations, useAddonsListJobs, useAddonsListPackages, useAddonsListUpdates, useAddonsOnAddonLogs, useAddonsReloadPackages, useAddonsRestartAddon, useAddonsRestartServer, useAddonsRetryLoad, useAddonsRollbackPackage, useAddonsSearchAvailable, useAddonsSetAddonAutoUpdate, useAddonsSetAutoUpdateSettings, useAddonsSetCapabilityProviderEnabled, useAddonsStartJob, useAddonsUninstallPackage, useAddonsUpdatePackage, useAirQualitySensorGetStatus, useAlarmPanelArm, useAlarmPanelDisarm, useAlarmPanelGetStatus, useAlarmPanelTrigger, useAlert, useAlertsDismiss, useAlertsEmit, useAlertsGetUnreadCount, useAlertsList, useAlertsMarkAllRead, useAlertsMarkRead, useAlertsUpdate, useAllWidgets, useAmbientLightSensorGetStatus, useAudioAnalysisApplyDeviceSettingsPatch, useAudioAnalysisGetDeviceLiveContribution, useAudioAnalysisGetDeviceSettingsContribution, useAudioAnalysisResolveDeviceSettings, useAudioAnalyzerAnalyseChunk, useAudioAnalyzerAttachDevice, useAudioAnalyzerClassify, useAudioAnalyzerDetachDevice, useAudioAnalyzerDispose, useAudioAnalyzerIsReady, useAudioAnalyzerReprobeAudioEngine, useAudioCodecCanHandle, useAudioCodecCloseSession, useAudioCodecCreateDecodeSession, useAudioCodecCreateEncodeSession, useAudioCodecFlushEncode, useAudioCodecListActiveSessions, useAudioCodecListSupportedCodecs, useAudioCodecPullEncoded, useAudioCodecPullPcm, useAudioCodecPushEncodedFrame, useAudioCodecPushPcm, useAudioMetricsGetCurrentSnapshot, useAudioMetricsGetHistory, useAutomationControlDisable, useAutomationControlEnable, useAutomationControlGetStatus, useAutomationControlTrigger, useBackupCancel, useBackupCheckBackupKey, useBackupDelete, useBackupDeleteSchedule, useBackupDisableEncryption, useBackupGetEncryption, useBackupGetEntries, useBackupList, useBackupListArchives, useBackupListAvailableDatabases, useBackupListDestinations, useBackupListLocations, useBackupListRuns, useBackupListSchedules, useBackupPreviewSchedule, useBackupRestore, useBackupSetupEncryption, useBackupTrigger, useBackupUpsertDestinationPolicy, useBackupUpsertSchedule, useBatteryGetStatus, useBatteryWakeForStream, useBinaryGetStatus, useBrightnessGetStatus, useBrightnessSetBrightness, useBrokerAdd, useBrokerGet, useBrokerGetBrokerConfig, useBrokerGetSettings, useBrokerGetSettingsSchema, useBrokerGetState, useBrokerGetStatus, useBrokerList, useBrokerListProviders, useBrokerPickerSlot, useBrokerPublish, useBrokerRemove, useBrokerSetSettings, useBrokerSubscribe, useBrokerTestConnection, useBrokerTestSettings, useBrokerUnsubscribe, useButtonPress, useCalendarsGetPreferences, useCalendarsListCalendars, useCalendarsListEvents, useCalendarsSetCalendarPreference, useCameraCredentialsGetCredentials, useCameraCredentialsGetStatus, useCameraGridLayoutApplyDeviceSettingsPatch, useCameraGridLayoutGetDeviceLiveContribution, useCameraGridLayoutGetDeviceSettingsContribution, useCameraGridLayoutGetLayout, useCameraGridLayoutSaveLayout, useCameraPipelineConfigApplyDeviceSettingsPatch, useCameraPipelineConfigGetDeviceLiveContribution, useCameraPipelineConfigGetDeviceSettingsContribution, useCameraStreamsGetBrokerStreams, useCameraStreamsGetCameraStreams, useCameraStreamsGetProfileRtspEntries, useCameraStreamsGetRtspEntries, useCameraStreamsPickStream, useCapabilityPresence, useCarbonMonoxideGetStatus, useClassPainter, useClimateControlGetStatus, useClimateControlSetFanMode, useClimateControlSetMode, useClimateControlSetPreset, useClimateControlSetSwingHorizontal, useClimateControlSetSwingVertical, useClimateControlSetTarget, useClimateControlSetTargetHumidity, useClimateControlSetTargetRange, useClusterNodes, useClusterTopology, useColorGetStatus, useColorSetColor, useConfirm, useConnectionTestDescribeTest, useConnectionTestTestSettings, useConnectivityGetStatus, useConsumablesGetStatus, useConsumablesReset, useContactGetStatus, useContainerChildren, useControlGetStatus, useControlSetValue, useCoreBlocksCompile, useCoreBlocksCreate, useCoreBlocksCreateComposition, useCoreBlocksDelete, useCoreBlocksGet, useCoreBlocksGetAutomationRunState, useCoreBlocksGetBlockSettings, useCoreBlocksGetComposition, useCoreBlocksGetCustomization, useCoreBlocksGetTraces, useCoreBlocksGetTypeDefs, useCoreBlocksList, useCoreBlocksListComposableCaps, useCoreBlocksListCompositions, useCoreBlocksMigrateRawSecrets, useCoreBlocksReportAutomationRun, useCoreBlocksRestart, useCoreBlocksSetEnabled, useCoreBlocksUpdate, useCoreBlocksUpdateBlockSettings, useCoreBlocksUpdateComposition, useCoreBlocksValidateComposition, useCoverClose, useCoverGetStatus, useCoverOpen, useCoverSetPosition, useCoverSetTiltPosition, useCoverStop, useCustomFieldRenderer, useDataTableFilter, useDayNightGetOptions, useDayNightGetStatus, useDayNightSetSettings, useDebouncedString, useDecoderGetInfo, useDecoderReprobeHwaccel, useDetectionPipelineApplyDeviceSettingsPatch, useDetectionPipelineGetDeviceLiveContribution, useDetectionPipelineGetDeviceSettingsContribution, useDevShell, useDevice, useDeviceAdminLink, useDeviceAdminLinkGetAdminLink, useDeviceAdoptionAdopt, useDeviceAdoptionGetCandidate, useDeviceAdoptionGetStatus, useDeviceAdoptionListCandidateFilters, useDeviceAdoptionListCandidates, useDeviceAdoptionRefresh, useDeviceAdoptionRelease, useDeviceAdoptionResync, useDeviceAutotrack, useDeviceBattery, useDeviceCapSlice, useDeviceCapability, useDeviceCredentialsDeleteDeviceCredential, useDeviceCredentialsGetDeviceCaStatus, useDeviceCredentialsGetDeviceCertificateSettings, useDeviceCredentialsListDeviceCredentials, useDeviceCredentialsRenameDeviceCredential, useDeviceCredentialsRevokeDeviceCredential, useDeviceCredentialsSetDeviceCertificateSettings, useDeviceCredentialsStartEnrollment, useDeviceDetections, useDeviceDiscoveryAdoptDevice, useDeviceDiscoveryGetStatus, useDeviceDiscoveryListDiscovered, useDeviceDiscoveryRefreshDiscovery, useDeviceDiscoveryReleaseDevice, useDeviceExportApplyDeviceSettingsPatch, useDeviceExportExposeDevice, useDeviceExportExposeEntity, useDeviceExportGetDeviceLiveContribution, useDeviceExportGetDeviceSettingsContribution, useDeviceExportGetStatus, useDeviceExportListExposedDevices, useDeviceExportListExposedEntities, useDeviceExportListSupportedDeviceKinds, useDeviceExportListSupportedEntityKinds, useDeviceExportUnexposeDevice, useDeviceExportUnexposeEntity, useDeviceExtensionListCandidates, useDeviceExtensionListSlots, useDeviceExtensionListSources, useDeviceExtensionSetSlot, useDeviceHistoryDeclareSeries, useDeviceHistoryDeleteOrphanSeries, useDeviceHistoryGetDeviceEnabled, useDeviceHistoryGetStatus, useDeviceHistoryListNodeSeries, useDeviceHistoryListOrphanSeries, useDeviceHistoryListSeries, useDeviceHistoryQuery, useDeviceHistoryQueryMany, useDeviceHistoryQueryNode, useDeviceHistoryRecord, useDeviceHistoryRecordBuckets, useDeviceHistorySetDeviceEnabled, useDeviceId, useDeviceLabel, useDeviceLabelById, useDeviceListPageSize, useDeviceManagerAddLocation, useDeviceManagerAdoptDevice, useDeviceManagerAdoptionAdopt, useDeviceManagerAdoptionCancelJob, useDeviceManagerAdoptionListCandidateFilters, useDeviceManagerAdoptionListCandidates, useDeviceManagerAdoptionListJobs, useDeviceManagerAdoptionRefresh, useDeviceManagerAdoptionRelease, useDeviceManagerAdoptionResync, useDeviceManagerAdoptionStartJob, useDeviceManagerAllocateDeviceId, useDeviceManagerApplyInitialMeta, useDeviceManagerCleanupDeletedDevicesData, useDeviceManagerCreateDevice, useDeviceManagerDisable, useDeviceManagerDiscoverAllProviders, useDeviceManagerDiscoverDevices, useDeviceManagerDiscoverProvider, useDeviceManagerDiscoveryProviders, useDeviceManagerEnable, useDeviceManagerGetAllBindings, useDeviceManagerGetBindings, useDeviceManagerGetBindingsBatch, useDeviceManagerGetChildren, useDeviceManagerGetChildrenBatch, useDeviceManagerGetConfigSchema, useDeviceManagerGetCreationSchema, useDeviceManagerGetDevice, useDeviceManagerGetDeviceAggregate, useDeviceManagerGetDeviceLiveInfoAggregate, useDeviceManagerGetDeviceSettingsAggregate, useDeviceManagerGetDeviceStatusAggregate, useDeviceManagerGetDeviceStatusAggregateBatch, useDeviceManagerGetLinkedDevices, useDeviceManagerGetLinkedDevicesBatch, useDeviceManagerGetRoleDisplayDefaults, useDeviceManagerGetSettingsSchema, useDeviceManagerGetStreamProfileMap, useDeviceManagerGetStreamSources, useDeviceManagerGetWireableFields, useDeviceManagerGetWrapperActivation, useDeviceManagerListAll, useDeviceManagerListBindableCapsForDeviceType, useDeviceManagerListDeletedSince, useDeviceManagerListDeviceIdsByCaps, useDeviceManagerListLocationDescriptions, useDeviceManagerListLocationIcons, useDeviceManagerListLocations, useDeviceManagerListPersistedByAddon, useDeviceManagerListSiteZones, useDeviceManagerListWrappersForCap, useDeviceManagerLoadConfig, useDeviceManagerLoadMeta, useDeviceManagerLoadRuntimeState, useDeviceManagerMigrateDevice, useDeviceManagerPersistConfig, useDeviceManagerProbeStreams, useDeviceManagerProviderCreationType, useDeviceManagerProviderDiscoveryParamsSchema, useDeviceManagerRegisterDevice, useDeviceManagerRemove, useDeviceManagerRemoveByIntegration, useDeviceManagerRemoveDevice, useDeviceManagerRemoveLocation, useDeviceManagerRemoveSiteZone, useDeviceManagerRenameLocation, useDeviceManagerRenameSiteZone, useDeviceManagerRunDeviceAction, useDeviceManagerSetChildLayout, useDeviceManagerSetDisabled, useDeviceManagerSetDisplay, useDeviceManagerSetIntegrationId, useDeviceManagerSetLinkDeviceId, useDeviceManagerSetLocation, useDeviceManagerSetLocationDescription, useDeviceManagerSetLocationIcon, useDeviceManagerSetLocationZone, useDeviceManagerSetMetadata, useDeviceManagerSetName, useDeviceManagerSetPrimaryChildEntityId, useDeviceManagerSetRole, useDeviceManagerSetRoleDisplayDefaults, useDeviceManagerSetSiteZone, useDeviceManagerSetStreamProfileMap, useDeviceManagerSetType, useDeviceManagerSetWrapperActive, useDeviceManagerTestCreationField, useDeviceManagerTestField, useDeviceManagerUpdateConfig, useDeviceManagerUpdateDeviceField, useDeviceManagerUpdateDeviceFieldsBatch, useDeviceNameIndex, useDeviceNameNouns, useDeviceNetworkLink, useDeviceOpsGetConfigEntries, useDeviceOpsGetRawState, useDeviceOpsGetSettingsSchema, useDeviceOpsGetStreamSources, useDeviceOpsRemoveDevice, useDeviceOpsRunAction, useDeviceOpsSetConfig, useDeviceProviderAdoptDiscoveredDevice, useDeviceProviderClassifyDiscoveryHits, useDeviceProviderCreateDevice, useDeviceProviderDiscoverDevices, useDeviceProviderGetChildCreationSchema, useDeviceProviderGetDevices, useDeviceProviderGetDiscoveryModes, useDeviceProviderGetDiscoveryParamsSchema, useDeviceProviderGetManualCreationType, useDeviceProviderGetStatus, useDeviceProviderReloadDevice, useDeviceProviderStart, useDeviceProviderStop, useDeviceProviderSupportsDiscovery, useDeviceProviderSupportsManualCreation, useDeviceProviderTestCreationField, useDeviceProxy, useDeviceQuickDetailOpen, useDeviceRunsGetCurrentRun, useDeviceRunsGetRun, useDeviceRunsListRuns, useDeviceSeriesList, useDeviceSnapshot, useDeviceSnapshotImage, useDeviceState, useDeviceStateClaimFields, useDeviceStateGetAllSnapshots, useDeviceStateGetCapSlice, useDeviceStateGetNativeCapSlice, useDeviceStateGetSnapshot, useDeviceStateListClaims, useDeviceStatePatchOwnedFields, useDeviceStateReleaseClaim, useDeviceStateSetCapSlice, useDeviceStateSlice, useDeviceStatusGetStatus, useDeviceWebrtc, useDevices, useDiscoveredOptions, useDishwasherGetOptions, useDishwasherGetStatus, useDishwasherPause, useDishwasherResume, useDishwasherSetChildLock, useDishwasherSetExtraDry, useDishwasherSetHalfLoad, useDishwasherSetHygienePlus, useDishwasherSetIntensiveZone, useDishwasherSetOption, useDishwasherSetPower, useDishwasherSetProgram, useDishwasherSetVarioSpeedPlus, useDishwasherStart, useDishwasherStop, useDisplayIconResolver, useDisplayPaletteGetPalette, useDisplayPaletteListPresets, useDisplayPaletteSetPalette, useDisplayPaletteView, useDoorbellEvents, useDoorbellGetStatus, useEnumSensorGetStatus, useEventEmitterGetStatus, useEventInvalidation, useEventStreamLatest, useEventStreamMap, useFaceGalleryAssignFace, useFaceGalleryAssignFaces, useFaceGalleryAuditIdentitySamples, useFaceGalleryCreateIdentity, useFaceGalleryDeleteFace, useFaceGalleryDeleteIdentity, useFaceGalleryGetFaceByTrack, useFaceGalleryGetFaceMedia, useFaceGalleryListIdentities, useFaceGalleryListIdentitySamples, useFaceGalleryListRecentFaces, useFaceGalleryRemoveSample, useFaceGalleryRenameIdentity, useFaceGallerySuggestFaceClusters, useFaceGalleryUnassignFace, useFaceGalleryUnassignFaces, useFanControlGetStatus, useFanControlSetDirection, useFanControlSetOscillating, useFanControlSetPercentage, useFanControlSetPreset, useFeatureProbeGetStatus, useFloodGetStatus, useGasGetStatus, useGroupActiveGetStatus, useGroupCommandsGetStatus, useGroupStatusGetStatus, useHeatingValveGetStatus, useHistoryPanels, useHistoryReader, useHistoryReads, useHotkey, useHumidifierGetStatus, useHumidifierSetMode, useHumidifierSetOn, useHumidifierSetTargetHumidity, useHumiditySensorGetStatus, useIconGlyphsVersion, useImageGetStatus, useImageSettingsGetOptions, useImageSettingsGetStatus, useImageSettingsSetSettings, useIntegrationsCreate, useIntegrationsDelete, useIntegrationsGet, useIntegrationsGetAvailableTypes, useIntegrationsGetByAddonId, useIntegrationsGetSettings, useIntegrationsList, useIntegrationsSetSettings, useIntegrationsTestConnection, useIntegrationsUpdate, useIntercomEndTalkSession, useIntercomGetStatus, useIntercomHandleAnswer, useIntercomPushTalkAudio, useIntercomStartSession, useIntercomStartTalkSession, useIntercomStopSession, useIrTransmitterGetInfo, useIrTransmitterSend, useIsMidWidth, useIsMobile, useItemFormUrl, useKeychainAdminAcknowledgeReset, useKeychainAdminDeleteOrphans, useKeychainAdminDownloadRecoveryKey, useKeychainAdminImportSecret, useKeychainAdminListAudit, useKeychainAdminListSecrets, useKeychainAdminPurgeRetiredKeys, useKeychainAdminResetKeychain, useKeychainAdminResetReport, useKeychainAdminReveal, useKeychainAdminRotateMasterKey, useKeychainAdminSetSystemSecret, useKeychainAdminStatus, useLawnMowerControlDock, useLawnMowerControlGetStatus, useLawnMowerControlPause, useLawnMowerControlStartMowing, useLiveBuffer, useLiveEvent, useLlmCancel, useLlmDeleteModel, useLlmDeleteProfile, useLlmGenerate, useLlmGenerateVision, useLlmGetDefaults, useLlmGetRuntimeStatus, useLlmGetUsage, useLlmInstallModel, useLlmListModelCatalog, useLlmListModels, useLlmListNodeModels, useLlmListProfileKinds, useLlmListProfiles, useLlmListRuntimeNodes, useLlmMigrateRawSecrets, useLlmResolveModelRef, useLlmSetDefault, useLlmStartRuntime, useLlmStopRuntime, useLlmTestProfile, useLlmUpsertProfile, useLocalNetworkAddCustomAddress, useLocalNetworkDownloadCa, useLocalNetworkGetAddresses, useLocalNetworkGetAllowedAddresses, useLocalNetworkGetConnectionEndpoints, useLocalNetworkGetHubAddresses, useLocalNetworkGetNotificationEndpoint, useLocalNetworkGetPreferred, useLocalNetworkGetScanSubnets, useLocalNetworkGetTlsStatus, useLocalNetworkGetViewerEndpoints, useLocalNetworkList, useLocalNetworkRegenerateCertificate, useLocalNetworkRemoveCustomAddress, useLocalNetworkResetAllowlistToBestMatch, useLocalNetworkRevertToGeneratedCertificate, useLocalNetworkScanNetwork, useLocalNetworkSetAddressRole, useLocalNetworkSetAllowedAddresses, useLocalNetworkSetNotificationEndpoint, useLocalNetworkSetScanSubnets, useLocalNetworkSetViewerEndpoints, useLocalNetworkUploadCertificate, useLocalNetworkUseStoredUploadedCertificate, useLockControlGetStatus, useLockControlLock, useLockControlOpen, useLockControlUnlock, useLockDoorSensor, useMediaPlayerGetStatus, useMediaPlayerNext, useMediaPlayerPause, useMediaPlayerPlay, useMediaPlayerPlayMedia, useMediaPlayerPrevious, useMediaPlayerSeek, useMediaPlayerSelectSource, useMediaPlayerSetMute, useMediaPlayerSetRepeat, useMediaPlayerSetShuffle, useMediaPlayerSetVolume, useMediaPlayerStop, useMeshNetworkGetStatus, useMeshNetworkJoin, useMeshNetworkLeave, useMeshNetworkListPeers, useMeshNetworkLogout, useMeshNetworkStartLogin, useMeshNetworkTestConnection, useMeterGetStatus, useMetricsProviderCollectSnapshot, useMetricsProviderGetAddonStats, useMetricsProviderGetCached, useMetricsProviderGetCpuTemperature, useMetricsProviderGetCurrent, useMetricsProviderGetDiskSpace, useMetricsProviderGetGpuInfo, useMetricsProviderGetLoadSeries, useMetricsProviderGetProcessStats, useMetricsProviderListAddonInstances, useMetricsProviderListNodeProcesses, useMotionDetectionAnalyze, useMotionDetectionApplyDeviceSettingsPatch, useMotionDetectionGetDeviceLiveContribution, useMotionDetectionGetDeviceSettingsContribution, useMotionDetectionRemoveCamera, useMotionDetectionReset, useMotionGetStatus, useMotionIsDetected, useMotionTriggerGetStatus, useMotionTriggerSetMotionTrigger, useMotionZonesGetOptions, useMotionZonesGetStatus, useMotionZonesSetZone, useMqttBrokerAddBroker, useMqttBrokerGetBrokerConfig, useMqttBrokerGetStatus, useMqttBrokerListBrokers, useMqttBrokerRemoveBroker, useMqttBrokerStartEmbeddedBroker, useMqttBrokerStopEmbeddedBroker, useMqttBrokerTestConnection, useNativeObjectDetectionGetOptions, useNativeObjectDetectionGetStatus, useNativeObjectDetectionSetEnabled, useNativeObjectDetectionSetSettings, useNavigation, useNavigationGetFeatures, useNavigationGetStatus, useNavigationGoToPoint, useNavigationListActions, useNavigationMove, useNavigationPlaySound, useNavigationRunAction, useNavigationSetLightLevel, useNavigationSetLightMode, useNavigationSetLightOn, useNavigationStop, useNetworkAccessGetEndpoint, useNetworkAccessGetStatus, useNetworkAccessListEndpoints, useNetworkAccessStart, useNetworkAccessStop, useNetworkLinkGetStatus, useNetworkQualityGetAllStats, useNetworkQualityGetDeviceStats, useNetworkQualityReportClientStats, useNodesClusterAddonStatus, useNodesDeployAddon, useNodesDirectory, useNodesExecuteQuery, useNodesGetCapUsageGraph, useNodesGetNodeAddons, useNodesRenameNode, useNodesRestartAddon, useNodesRestartNode, useNodesRestartProcess, useNodesSetProcessLogLevel, useNodesShutdownNode, useNodesTopology, useNodesUndeployAddon, useNotificationOutputDeleteTarget, useNotificationOutputDiscoverTargets, useNotificationOutputGetTarget, useNotificationOutputListTargetKinds, useNotificationOutputListTargets, useNotificationOutputProbeTargetConfig, useNotificationOutputSend, useNotificationOutputSetTargetEnabled, useNotificationOutputTestTarget, useNotificationOutputUpsertTarget, useNotificationRulesActivateAlarmProfile, useNotificationRulesCancelSnooze, useNotificationRulesCreateAlarmProfile, useNotificationRulesCreateRule, useNotificationRulesCreateSequence, useNotificationRulesCreateSnooze, useNotificationRulesDeleteAlarmProfile, useNotificationRulesDeleteRule, useNotificationRulesDeleteSequence, useNotificationRulesGetAlarmConfig, useNotificationRulesGetAlarmSensors, useNotificationRulesGetClipRetentionAsks, useNotificationRulesGetConditionCatalog, useNotificationRulesGetHistory, useNotificationRulesGetRule, useNotificationRulesGetRuleLastRuns, useNotificationRulesGetSequence, useNotificationRulesGetTemplateCatalog, useNotificationRulesListDeviceMutes, useNotificationRulesListRules, useNotificationRulesListSequences, useNotificationRulesListSnoozes, useNotificationRulesPreviewStateSummary, useNotificationRulesPreviewTemplate, useNotificationRulesRenameAlarmProfile, useNotificationRulesResolveArtifactUrl, useNotificationRulesSetAlarmConfig, useNotificationRulesSetDeviceMuted, useNotificationRulesSetRuleEnabled, useNotificationRulesTestRule, useNotificationRulesUpdateRule, useNotificationRulesUpdateSequence, useNotifierCancel, useNotifierGetStatus, useNotifierSend, useNumericSensorGetStatus, useOidcConnectionsConnectionFormSchema, useOidcConnectionsCreateConnection, useOidcConnectionsDeleteConnection, useOidcConnectionsListConnections, useOidcConnectionsUpdateConnection, useOptimisticSlice, useOptionalSystem, useOptionalWidgetRegistry, useOsdGetStatus, useOsdManagerClearSlotBinding, useOsdManagerCopyDeviceConfiguration, useOsdManagerDeleteTemplate, useOsdManagerGetConditionSupport, useOsdManagerGetDeviceOsd, useOsdManagerGetSourceCatalog, useOsdManagerListTemplates, useOsdManagerPreviewSlot, useOsdManagerRenderDevice, useOsdManagerSetSlotBinding, useOsdManagerSetSlotCameraEnabled, useOsdManagerUpsertTemplate, useOsdSetOverlay, usePTZ, usePersistedDisclosure, usePersistedPageSize, usePetFeederCallPet, usePetFeederCancelFeed, usePetFeederFeed, usePetFeederGetStatus, usePetFeederMarkFoodReplenished, usePetFeederPlaySound, usePetFeederResetDesiccant, usePetFeederSetChildLock, usePetFeederSetFeedSound, usePetFeederSetIndicatorLight, usePetFeederSetVolume, usePetFountainGetStatus, usePetFountainResetDailyConsumption, usePetFountainSetPump, usePetFountainSetPumpInterval, usePetFountainSetPumpOffMinutes, usePetFountainSetPumpOnMinutes, usePickerSiteZones, usePipelineAnalyticsAddRetrainFrameFromRecording, usePipelineAnalyticsAddRetrainFramesToCollection, usePipelineAnalyticsApplyDeviceSettingsPatch, usePipelineAnalyticsBackfillRetrainOrigins, usePipelineAnalyticsCancelRelocateMedia, usePipelineAnalyticsCancelStorageMigrationMove, usePipelineAnalyticsClearTrackRelation, usePipelineAnalyticsClearTracks, usePipelineAnalyticsCompleteRetrainTrack, usePipelineAnalyticsCountRelocatableMedia, usePipelineAnalyticsCountUnstampedEventMedia, usePipelineAnalyticsCreateRetrainCollection, usePipelineAnalyticsDeleteDeviceEvents, usePipelineAnalyticsDeleteRetrainCollection, usePipelineAnalyticsDeleteTracks, usePipelineAnalyticsDeselectRetrainFrame, usePipelineAnalyticsGetActiveTracks, usePipelineAnalyticsGetAudioEvents, usePipelineAnalyticsGetDeviceLiveContribution, usePipelineAnalyticsGetDeviceSettingsContribution, usePipelineAnalyticsGetEventDensity, usePipelineAnalyticsGetEventDensityBatch, usePipelineAnalyticsGetEventMedia, usePipelineAnalyticsGetEventMediaFootprintByKind, usePipelineAnalyticsGetEventStoreFootprint, usePipelineAnalyticsGetKeyEvents, usePipelineAnalyticsGetKeyEventsBatch, usePipelineAnalyticsGetMediaReclaimStatus, usePipelineAnalyticsGetMotionEvents, usePipelineAnalyticsGetObjectEmbeddingRebuildStatus, usePipelineAnalyticsGetObjectEvents, usePipelineAnalyticsGetRetrainCorpusKpi, usePipelineAnalyticsGetRetrainExportUrl, usePipelineAnalyticsGetRetrainFrameImage, usePipelineAnalyticsGetSensorEvents, usePipelineAnalyticsGetStorageMigrationMoveStatus, usePipelineAnalyticsGetTrack, usePipelineAnalyticsGetTrackMedia, usePipelineAnalyticsGetTrainingExportSummary, usePipelineAnalyticsGetTrainingExportUrl, usePipelineAnalyticsListArchivedDebugNotes, usePipelineAnalyticsListBirthDecisions, usePipelineAnalyticsListEventKinds, usePipelineAnalyticsListEventKindsBatch, usePipelineAnalyticsListEventMedia, usePipelineAnalyticsListOpsLog, usePipelineAnalyticsListRecentTracks, usePipelineAnalyticsListRelocateMediaJobs, usePipelineAnalyticsListRetrainAnnotations, usePipelineAnalyticsListRetrainAssistProfiles, usePipelineAnalyticsListRetrainCollectionFrames, usePipelineAnalyticsListRetrainCollections, usePipelineAnalyticsListRetrainCorpusPage, usePipelineAnalyticsListRetrainFrames, usePipelineAnalyticsListRetrainStaging, usePipelineAnalyticsListTrackMedia, usePipelineAnalyticsListTrackRelations, usePipelineAnalyticsListTracks, usePipelineAnalyticsOfferRetrainArchive, usePipelineAnalyticsOwnersWithMedia, usePipelineAnalyticsPauseForStorageMigration, usePipelineAnalyticsProposeRetrainAnnotations, usePipelineAnalyticsProposeRetrainAnnotationsWithLlm, usePipelineAnalyticsPruneEvents, usePipelineAnalyticsPruneEventsBefore, usePipelineAnalyticsPruneTracksBefore, usePipelineAnalyticsReadLongTermSeries, usePipelineAnalyticsRebuildObjectEmbeddings, usePipelineAnalyticsReclaimDebugMedia, usePipelineAnalyticsReconcileFromDisk, usePipelineAnalyticsRefreshStorageLocationsForMigration, usePipelineAnalyticsRelocateMedia, usePipelineAnalyticsRemoveRetrainFrameFromCollection, usePipelineAnalyticsRenameRetrainCollection, usePipelineAnalyticsResolveRetrainTrainingCorpus, usePipelineAnalyticsRestageRetrainTrack, usePipelineAnalyticsResumeForStorageMigration, usePipelineAnalyticsSaveRetrainAnnotations, usePipelineAnalyticsSearchObjectEvents, usePipelineAnalyticsSelectRetrainFrames, usePipelineAnalyticsSetRetrainFrameComplete, usePipelineAnalyticsSetTrackFlags, usePipelineAnalyticsSetTrackPurity, usePipelineAnalyticsSetTrackRelation, usePipelineAnalyticsStartStorageMigrationMove, usePipelineAnalyticsWipeAllAnalytics, usePipelineAnalyticsWipeObjectEmbeddings, usePipelineAnalyticsWriteRetrainArchive, usePipelineExecutorCacheFrameInPool, usePipelineExecutorDeleteModel, usePipelineExecutorDownloadModel, usePipelineExecutorGetAddonModels, usePipelineExecutorGetAudioCapabilities, usePipelineExecutorGetAvailableEngines, usePipelineExecutorGetCapabilities, usePipelineExecutorGetDetectionConfigSchema, usePipelineExecutorGetEffectiveTuning, usePipelineExecutorGetEngineProvisioning, usePipelineExecutorGetInferenceDeviceHealth, usePipelineExecutorGetOrchestratorConfigSchema, usePipelineExecutorGetReferenceAudio, usePipelineExecutorGetReferenceAudioFiles, usePipelineExecutorGetReferenceImage, usePipelineExecutorGetSchema, usePipelineExecutorGetSelectedEngine, usePipelineExecutorGetVideoPipelineSteps, usePipelineExecutorInferCached, usePipelineExecutorKillEngine, usePipelineExecutorListLoadedEngines, usePipelineExecutorListReferenceImages, usePipelineExecutorRearmInferenceDevice, usePipelineExecutorRunAudioTest, usePipelineExecutorRunPipeline, usePipelineExecutorRunPipelineBatch, usePipelineExecutorSetVideoPipelineSteps, usePipelineExecutorSpinEngine, usePipelineExecutorUncacheFrame, usePipelineExecutorValidatePipeline, usePipelineOrchestratorAbortNodeBenchmark, usePipelineOrchestratorApplyAutoTune, usePipelineOrchestratorApplyDeviceSettingsPatch, usePipelineOrchestratorAssignAudio, usePipelineOrchestratorAssignPipeline, usePipelineOrchestratorDeleteNodeBenchmarkResult, usePipelineOrchestratorForgetInferenceDevice, usePipelineOrchestratorGetAgentLoad, usePipelineOrchestratorGetAgentSettings, usePipelineOrchestratorGetAudioAssignment, usePipelineOrchestratorGetAudioAssignments, usePipelineOrchestratorGetAudioNodeLoad, usePipelineOrchestratorGetCameraDetectionSource, usePipelineOrchestratorGetCameraMetrics, usePipelineOrchestratorGetCameraSettings, usePipelineOrchestratorGetCameraStatus, usePipelineOrchestratorGetCameraStatuses, usePipelineOrchestratorGetCameraSwitches, usePipelineOrchestratorGetCapabilityBindings, usePipelineOrchestratorGetClusterModelChoice, usePipelineOrchestratorGetDeviceLiveContribution, usePipelineOrchestratorGetDeviceSettingsContribution, usePipelineOrchestratorGetEffectiveShares, usePipelineOrchestratorGetGlobalMetrics, usePipelineOrchestratorGetIngestOwner, usePipelineOrchestratorGetNodeBenchmarkCandidates, usePipelineOrchestratorGetNodeBenchmarkPreflight, usePipelineOrchestratorGetNodeBenchmarkStatus, usePipelineOrchestratorGetNodeInferenceDevices, usePipelineOrchestratorGetPipelineAssignment, usePipelineOrchestratorGetPipelineAssignments, usePipelineOrchestratorGetPipelineDevicePin, usePipelineOrchestratorGetPlacementStats, usePipelineOrchestratorGetReconcileFromDiskStatus, usePipelineOrchestratorListAgentSettings, usePipelineOrchestratorListNodeBenchmarkResults, usePipelineOrchestratorPauseForStorageMigration, usePipelineOrchestratorPlanAutoTune, usePipelineOrchestratorRebalance, usePipelineOrchestratorReconcileFromDisk, usePipelineOrchestratorRemoveAgentSettings, usePipelineOrchestratorRequestOccupancyLook, usePipelineOrchestratorResetNodePipelineDefaults, usePipelineOrchestratorResolvePipeline, usePipelineOrchestratorResumeForStorageMigration, usePipelineOrchestratorSetAgentCapabilities, usePipelineOrchestratorSetAgentDecodeLimits, usePipelineOrchestratorSetAgentInferenceDevices, usePipelineOrchestratorSetAgentMaxCameras, usePipelineOrchestratorSetAgentReachableHost, usePipelineOrchestratorSetCameraDetectionSource, usePipelineOrchestratorSetCameraSensors, usePipelineOrchestratorSetCameraStepSettings, usePipelineOrchestratorSetCameraStepToggle, usePipelineOrchestratorSetCameraSwitch, usePipelineOrchestratorSetCapabilityBinding, usePipelineOrchestratorSetLoadBalancingShares, usePipelineOrchestratorSetNodeStepSettings, usePipelineOrchestratorSetPipelineDevicePin, usePipelineOrchestratorSetShareSource, usePipelineOrchestratorStartNodeBenchmark, usePipelineOrchestratorSuggestShares, usePipelineOrchestratorUnassignAudio, usePipelineOrchestratorUnassignPipeline, usePipelineRunnerAbortNodeBench, usePipelineRunnerAttachCamera, usePipelineRunnerDetachCamera, usePipelineRunnerGetAllCameraMetrics, usePipelineRunnerGetCameraMetrics, usePipelineRunnerGetLocalCameras, usePipelineRunnerGetLocalLoad, usePipelineRunnerGetLocalMetrics, usePipelineRunnerGetNativeCrop, usePipelineRunnerGetNodeBenchStatus, usePipelineRunnerGetParkedTrackFrame, usePipelineRunnerParkTrackFrame, usePipelineRunnerReleaseParkedTrackFrames, usePipelineRunnerReportMotion, usePipelineRunnerRequestOccupancyBurst, usePipelineRunnerRunDetailSubtree, usePipelineRunnerRunStatelessStep, usePipelineRunnerStartNodeBench, usePlateGalleryAssignPlate, usePlateGalleryAssignPlates, usePlateGalleryCorrectPlateText, usePlateGalleryCreateVehicle, usePlateGalleryDeletePlate, usePlateGalleryDeleteVehicle, usePlateGalleryGetPlateByTrack, usePlateGalleryGetPlateMedia, usePlateGalleryListPlates, usePlateGalleryListVehicleSamples, usePlateGalleryListVehicles, usePlateGalleryRemoveVehicleSample, usePlateGalleryRenameVehicle, usePlateGallerySearchPlates, usePlateGallerySuggestPlateClusters, usePlateGalleryUnassignPlate, usePlateGalleryUnassignPlates, usePlatformProbeGetCapabilities, usePlatformProbeGetHardware, usePlatformProbeRescanAccelerators, usePlatformProbeResolveHwAccel, usePlatformProbeResolveInferenceConfig, usePlayerOverlayLayer, usePlayerOverlayLayers, usePlayerToolbarButton, usePlayerToolbarButtons, usePowerMeterGetStatus, usePowerSourceForceRestart, usePowerSourceGetStatus, usePowerSourcePowerOff, usePowerSourcePowerOn, usePresenceGetStatus, usePressureSensorGetStatus, usePrivacyMaskGetOptions, usePrivacyMaskGetStatus, usePrivacyMaskSetAudioEnabled, usePrivacyMaskSetMask, usePrompt, usePtzAutotrackGetSettings, usePtzAutotrackGetStatus, usePtzAutotrackSetEnabled, usePtzAutotrackSetSettings, usePtzCaptureHomeHere, usePtzContinuousMove, usePtzDeletePreset, usePtzGetHomePreset, usePtzGetHomeReturn, usePtzGetOptions, usePtzGetPosition, usePtzGetPresets, usePtzGetStatus, usePtzGoHome, usePtzGoToPreset, usePtzMove, usePtzSavePreset, usePtzSetAutofocus, usePtzSetHomePreset, usePtzSetHomeReturn, usePtzStop, useRebootReboot, useRecordEntriesDeleteEntry, useRecordEntriesListEntries, useRecordEntriesListEntryKinds, useRecordEntriesPutEntry, useRecordedPlayback, useRecordingArchiveApplyDeviceSettingsPatch, useRecordingArchiveCancelRelocateJob, useRecordingArchiveCancelStorageMigrationMove, useRecordingArchiveDeleteFootprint, useRecordingArchiveGetAvailabilityBatch, useRecordingArchiveGetDaysWithRecordingsBatch, useRecordingArchiveGetDeviceConfig, useRecordingArchiveGetDeviceLiveContribution, useRecordingArchiveGetDeviceSettingsContribution, useRecordingArchiveGetPlacement, useRecordingArchiveGetRelocateResidue, useRecordingArchiveGetStatus, useRecordingArchiveGetStorageMigrationMoveStatus, useRecordingArchiveGetStorageUsage, useRecordingArchiveListOpsLog, useRecordingArchiveListRelocateJobs, useRecordingArchiveLocateSegment, useRecordingArchivePauseForStorageMigration, useRecordingArchivePlanStorageRebalance, useRecordingArchivePruneFootage, useRecordingArchiveReadGopBytes, useRecordingArchiveReadSegmentBytes, useRecordingArchiveReadWindowBytes, useRecordingArchiveReconcileLedgerAgainstDisk, useRecordingArchiveRefreshStorageLocationsForMigration, useRecordingArchiveRelocateFootage, useRecordingArchiveRenderClip, useRecordingArchiveRenderGif, useRecordingArchiveRescanStorage, useRecordingArchiveResumeForStorageMigration, useRecordingArchiveSetDeviceConfig, useRecordingArchiveSetDevicePlacement, useRecordingArchiveStartStorageMigrationMove, useRecordingArchiveStartStorageRebalance, useRecordingExportCancelExport, useRecordingExportCreateExport, useRecordingExportDeleteExport, useRecordingExportGetDownloadUrl, useRecordingExportGetExport, useRecordingExportListExports, useRecordingExportReadExportBytes, useRecordingGetAvailability, useRecordingGetDaysWithRecordings, useRecordingGetPlayback, useRecordingGetPlaybackOptions, useRecordingListSources, useRecordingOnboardGetOptions, useRecordingOnboardGetStatus, useRecordingOnboardSetSettings, useRecordingSignalGetStatus, useRemoteComponent, useRemoteGetConfig, useRemoteLayoutComponentsListComponents, useRemoteListCommands, useRemoteSendCommand, useRemoteSendMediaCommand, useRemoteSetConfig, useRoleDisplayDefaults, useRunningStateGetStatus, useSceneMonitorCaptureReference, useSceneMonitorCreateScene, useSceneMonitorDeleteReference, useSceneMonitorDeleteScene, useSceneMonitorGetStatus, useSceneMonitorListScenes, useSceneMonitorListScenesBatch, useSceneMonitorRecheckNow, useSceneMonitorResetScene, useSceneMonitorUpdateScene, useSchedulersConflicts, useSchedulersCreate, useSchedulersDelete, useSchedulersGet, useSchedulersGetStatus, useSchedulersGetTraces, useSchedulersList, useSchedulersPreview, useSchedulersSetEnabled, useSchedulersUpdate, useScriptRunnerGetStatus, useScriptRunnerRun, useScriptRunnerStop, useScrubController, useSearchFieldHotkey, useServerManagementApplyServerUpdate, useServerManagementCheckServerUpdate, useServerManagementGetLaunchOverrides, useServerManagementGetServerPackageStatus, useServerManagementInstallDesktopUpdate, useServerManagementRestartServer, useServerManagementRollbackServerUpdate, useServerManagementSetLaunchOverrides, useSettingsStoreAggregate, useSettingsStoreCount, useSettingsStoreDeclareCollection, useSettingsStoreDelete, useSettingsStoreDeleteWhere, useSettingsStoreGet, useSettingsStoreHistogram, useSettingsStoreInsert, useSettingsStoreInsertMany, useSettingsStoreIsEmpty, useSettingsStoreQuery, useSettingsStoreSet, useSettingsStoreTransact, useSettingsStoreUpdate, useSettingsStoreUpdateWhere, useSettingsStoreUpsert, useSettingsStoreUpsertMany, useSmokeGetStatus, useSnapshotApplyDeviceSettingsPatch, useSnapshotGetDebugState, useSnapshotGetDeviceLiveContribution, useSnapshotGetDeviceSettingsContribution, useSnapshotGetSnapshot, useSnapshotGetSnapshotLinks, useSnapshotGetSnapshotOverview, useSnapshotGetStatus, useSnapshotInvalidateCache, useStationaryOverlay, useStorageAbortUpload, useStorageBeginDownload, useStorageBeginUpload, useStorageDelete, useStorageDeleteLocation, useStorageEndDownload, useStorageExists, useStorageFinalizeUpload, useStorageGetAvailableSpace, useStorageList, useStorageListDrainProgress, useStorageListLocationDeclarations, useStorageListLocations, useStorageListProviders, useStorageMigrationCancel, useStorageMigrationCleanupCancel, useStorageMigrationCleanupStart, useStorageMigrationCleanupStatus, useStorageMigrationDrain, useStorageMigrationHistory, useStorageMigrationMoverClearance, useStorageMigrationMovers, useStorageMigrationPlan, useStorageMigrationResidue, useStorageMigrationStart, useStorageMigrationStatus, useStorageRead, useStorageReadChunk, useStorageResolve, useStorageTestConfig, useStorageTestLocation, useStorageUpsertLocation, useStorageWrite, useStorageWriteChunk, useStoredGroupBy, useStreamBrokerAcquireEgressTranscode, useStreamBrokerApplyDeviceSettingsPatch, useStreamBrokerAssignProfile, useStreamBrokerFetchEventMedia, useStreamBrokerForgetDeviceHardware, useStreamBrokerGetAllRtspEntries, useStreamBrokerGetBrokerStats, useStreamBrokerGetDeviceAudioMute, useStreamBrokerGetDeviceLiveContribution, useStreamBrokerGetDeviceSettingsContribution, useStreamBrokerGetLiveViewerCounts, useStreamBrokerGetPreBufferInfo, useStreamBrokerGetRtspEntry, useStreamBrokerGetRtspPort, useStreamBrokerGetStreamUrl, useStreamBrokerGetStreamWithCodec, useStreamBrokerIsRtspEnabled, useStreamBrokerKillClient, useStreamBrokerListAllCameraStreams, useStreamBrokerListAllProfileSlots, useStreamBrokerListClients, useStreamBrokerProbeStream, useStreamBrokerProduceEventMedia, useStreamBrokerPublishCameraStream, useStreamBrokerPullAudioChunks, useStreamBrokerRegenerateRtspToken, useStreamBrokerReleaseEgressTranscode, useStreamBrokerReleaseStreamWithCodec, useStreamBrokerRenderPreBufferClip, useStreamBrokerReportStreamSignal, useStreamBrokerRestartProfile, useStreamBrokerRetractCameraStream, useStreamBrokerSetDeviceAudioMute, useStreamBrokerSetPreBufferDuration, useStreamBrokerSetRtspEnabled, useStreamBrokerSubscribeAudioChunks, useStreamBrokerUnassignProfile, useStreamBrokerUnsubscribeAudioChunks, useStreamCatalogGetCatalog, useStreamParamsGetConfigSchema, useStreamParamsGetOptions, useStreamParamsGetStatus, useStreamParamsSetProfile, useStreamSignalsListSignals, useSwitchGetStatus, useSwitchSetState, useSystem, useSystemDetectSiteLocation, useSystemFeatureFlags, useSystemForceRetentionCleanup, useSystemGetFailureContributions, useSystemGetLoadContributions, useSystemGetLoggingSettings, useSystemGetRequestCensus, useSystemGetRetentionConfig, useSystemGetSiteLocation, useSystemHealth, useSystemInfo, useSystemMutation, useSystemNetworkAddresses, useSystemQuery, useSystemSetLoggingSettings, useSystemSetRetentionConfig, useSystemSetSiteLocation, useTamperGetStatus, useTemperatureSensorGetStatus, useTemplateCreate, useTemplateDelete, useTemplateGet, useTemplateList, useTemplateUpdate, useTerminalSessionAdoptLegacyMonitor, useTerminalSessionClose, useTerminalSessionCreateInstance, useTerminalSessionDeleteInstance, useTerminalSessionListInstances, useTerminalSessionListLegacyCameras, useTerminalSessionListProfiles, useTerminalSessionListSessions, useTerminalSessionOpenSession, useTerminalSessionPullOutput, useTerminalSessionResize, useTerminalSessionSetInstanceEnabled, useTerminalSessionUpdateInstance, useTerminalSessionWriteInput, useThemeMode, useToastOnToast, useTrainingCanaryResult, useTrainingCancelJob, useTrainingDiscardResult, useTrainingGetJob, useTrainingGetJobResult, useTrainingListBaseModels, useTrainingListCanaryTargets, useTrainingListJobs, useTrainingPlanJob, useTrainingRegisterResult, useTrainingRollbackCanary, useTrainingStartJob, useTrainingStartJobBatch, useTurnProviderGetTurnServers, useUiText, useUnitPreferences, useUpdateGetStatus, useUpdateInstallUpdate, useUrlQueryParam, useUserManagementConfirmTotp, useUserManagementCreateUser, useUserManagementDeleteUser, useUserManagementDisableTotp, useUserManagementFindUserByExternalIdentity, useUserManagementGetAdminBootstrapStatus, useUserManagementGetTotpStatus, useUserManagementListExternalIdentities, useUserManagementListOauthSessions, useUserManagementListUsers, useUserManagementMigrateRawSecrets, useUserManagementOauthExchangeCode, useUserManagementOauthIssueCode, useUserManagementOauthRefresh, useUserManagementOauthVerifyAccessToken, useUserManagementResetPassword, useUserManagementRevokeOauthSession, useUserManagementSetUserScopes, useUserManagementSetupTotp, useUserManagementUnlinkExternalIdentity, useUserManagementUpdateUser, useUserManagementValidateCredentials, useUserManagementVerifyTotp, useVacuumControlGetStatus, useVacuumControlLocate, useVacuumControlPause, useVacuumControlReturnToBase, useVacuumControlSetFanSpeed, useVacuumControlStart, useVacuumControlStop, useValveClose, useValveGetStatus, useValveOpen, useValveSetPosition, useValveStop, useVibrationGetStatus, useVideoclipsDialClipStream, useVideoclipsGetClipPlayback, useVideoclipsGetPlaybackOptions, useVideoclipsListClips, useVideoclipsListSources, useVideoclipsOfferClipBytes, useVideoclipsReadClipBytes, useVodPlayback, useWaterHeaterGetStatus, useWaterHeaterSetAway, useWaterHeaterSetOperationMode, useWaterHeaterSetTargetTemp, useWeatherGetStatus, useWebrtcSessionAddIceCandidate, useWebrtcSessionApplyDownlinkProbe, useWebrtcSessionCloseSession, useWebrtcSessionCreateSession, useWebrtcSessionGetIceCandidates, useWebrtcSessionGetSessionDebug, useWebrtcSessionGetSessionState, useWebrtcSessionHandleAnswer, useWebrtcSessionHandleOffer, useWebrtcSessionHasAdaptiveBitrate, useWebrtcSessionListStreams, useWidget, useWidgetMetadata, useWidgetRegistry, useZoneAnalyticsGetCameraHistory, useZoneAnalyticsGetCurrentSnapshot, useZoneAnalyticsGetCurrentSnapshotBatch, useZoneAnalyticsGetUnzonedHistory, useZoneAnalyticsGetZoneHistory, useZoneEditing, useZoneRulesListRules, useZoneRulesSetRules, useZonesAddZone, useZonesListZones, useZonesRemoveZone, useZonesUpdateZone, Sailboat as ut, UtensilsCrossed as v, vacuumStateMeta, validateScopes, valveStateMeta, variantLabel, HardDrive as vn, ChevronDown as vr, Radar as vt, Undo2 as w, waterHeaterPhase, waterHeaterTint, weatherConditionMeta, weatherTint, withHiddenChart, withPanel, withResolvedParentDetail, withUseRootModel, withoutModelScopedFields, withoutPanel, Gauge as wn, Camera as wr, writeStoredGroupBy, Plus as wt, UserCheck as x, GripHorizontal as xn, Cat as xr, Power as xt, Users as y, Hand as yn, Check as yr, QrCode$1 as yt, Sunrise as z, Droplets as zn, BatteryLow as zr, MoveHorizontal as zt };
73804
+ export { Ship as $, CloudSnow as $n, Activity as $r, Lock as $t, Trash2 as A, AddProviderEntryDialog, AddonGlobalSettingsForm, AdminLinkQuickAction, AgentStepEditor, AlarmHeroCard, AlarmInlineControl as AlarmPanelInlineControl, FlashlightOff as An, AppShell, Bot as Ar, ArcKnob, Phone as At, AudioClassificationList, AudioLevelWaveform, AudioWaveform, AutomationHeroCard, AutomationInlineControl, AutotrackSection, Sunrise as B, BATTERY_BADGE_LOW_KEY, BATTERY_BADGE_NORMAL_KEY, BINARY_BATTERY_LOW_BELOW, BOOLEAN_STATES, BTN_COMPACT, BTN_COMPACT_DANGER, BTN_COMPACT_PRIMARY, BTN_COMPACT_WARNING, BackToStepsButton, Badge, BarSeries, BatteryBadge, Droplets as Bn, BottomSheet, BatteryLow as Br, Breadcrumb, BrightnessPanel, BrokerPickerSlotProvider, MoveHorizontal as Bt, Button, ButtonControl, ButtonHeroCard, Unlink2 as C, CENTER, CHART_SERIES_TOKENS, CHIP_ACTIVE, CHIP_BASE, CHIP_INACTIVE, CLASS_COLORS, COLUMN_BREAKPOINT_CLASS, COLUMN_PRIORITY, COMMIT_DEDUPE_TOLERANCE_MS, COMMIT_DEDUPE_WINDOW_MS, CONSUMABLE_LOW_PERCENT, CONTROL_CAP_NAMES, CONTROL_FILLS, CameraStreamPlayer, Card, ChartFrame, ChartPlaceholder, ChartSwatch, ChartWindowToggle, Checkbox, ChildSectionAccordion, ClimatePanel, Grid2x2 as Cn, CodeBlock, CollapsibleCard, ConfigFormBuilder, FormField as ConfigFormField, ConfigNotificationTargetMultiSelectFieldView, ConfigNotificationTargetSelectFieldView, ConfigSchemaField, ConfirmActionButton, ConfirmDialogProvider, ConsumableLevelBadge, ConsumablesPanel, ContainerChildrenProvider, ContainerPrimaryHero, ControlColumn, ControlHeroCard, ControlInlineControl, ControlPanel, CopyButton, CoverHeroCard, CoverInlineControl, CoverPanel, Cast as Cr, PowerOff as Ct, CustomFieldRenderersProvider, TriangleAlert as D, DATA_RECORDS_KIND_PARAM, DATA_RECORDS_OWNER_PARAM, DATA_RECORD_FACET_GROUPS, DEFAULT_COLOR, DEFAULT_PAGINATION_LABELS, DEFAULT_UNIT_PREFERENCES, DEVICE_COLUMNS, DEVICE_EXPORT_PAGE_SIZE_KEY, DEVICE_LIST_PAGE_SIZE_KEY, DEVICE_LIST_PAGE_SIZE_OPTIONS, DEVICE_NAME_FORMS, DEVICE_NAME_JOIN, DEVICE_PICKER_GROUP_STORAGE_KEY, DEVICE_ROLE_META, DEVICE_ROLE_NOUNS, DEVICE_TYPE_CONTROL, DEVICE_TYPE_META, DEVICE_TYPE_NOUNS, DataRecordsHub, DataTable, DataTableFilterBar, DataTablePager, DetectionCanvas, DetectionOverlay, DetectionResultTree, DevShell, DeviceActivityPanel, DeviceBatchToolbar, DeviceCard, DeviceContextProvider, DeviceExportPanel, DeviceExportSetup, DeviceFilterBar, DeviceFleetFromServer, DeviceFleetProvider, DeviceGrid, DeviceHistoryView, DeviceItem, DeviceList, DeviceMultiSelectField, DeviceName, DevicePicker, DeviceQuickDetailProvider, DeviceSelectField, DeviceSelectorPicker, DeviceStepMatrix, DevicesFailedLine, DevicesLoadingLine, DevicesWidenWarning, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DisclosureChevron, DiscoveryPanel, DisplayPaletteProvider, Funnel as Dn, DoorbellRecentPanel, Bus as Dr, Dropdown, DropdownContent, DropdownItem, DropdownTrigger, Plane as Dt, DummyHeroCard, DummyInline, Truck as E, EMPTY_DATA_TABLE_FILTER, EMPTY_HISTORY_PANELS, EVENT_KIND_ICONS, EmptyState, Gamepad2 as En, EndpointResultsCard, EndpointTestCard, EntryJsonSchemaForm, Cable as Er, ErrorBox, Play as Et, EventKindGlyph, EventStream, ExtensionsPanel, Timer as F, FALLBACK_SCOPE, FAST_ICON_GLYPHS, FILL, FLEET_LIST_GC_TIME_MS, FLEET_LIST_QUERY_KEY, FLEET_LIST_STALE_TIME_MS, FanHeroCard, FanInlineControl, FanPanel, FileInput, FilterBar, FloatingEventStream, FloatingLogStream, FloatingPanel, Eye as Fn, FormField$1 as FormField, Bell as Fr, Network as Ft, Sprout as G, GAP_INTERVAL_FACTOR, GRID_GAP, GRID_PAIRED, GRID_QUICK_STATS, GateBadge, GateControl, Dog as Gn, ArrowUp as Gr, GripTrack, GroupedModelSelector, GroupedTilePicker, Minimize2 as Gt, SunMedium as H, HISTORY_PAGE_PATH, HISTORY_PANELS_NAMESPACE, HISTORY_SELECTION_MAX, HISTORY_WINDOW_IDS, HISTORY_WINDOW_MS, HOST_WIDGETS, HUB_SESSION_RUN_MS, HistoryChart, HistoryWindowBar, HlsVideo, Download as Hn, HotkeyProvider, HotkeyScope, HoverZoomImage, Bath as Hr, Moon as Ht, HubSessionTestCard, HumidifierHeroCard, HumidifierInlineControl, TimerOff as I, INPUT_COMPACT, INPUT_SHELL, IconAction, IconButton, IconPicker, ImageHeroCard, ImageInlineControl, ImageSelector, EyeOff as In, InferenceConfigSelector, Input, BellRing as Ir, Navigation as It, ItemFormDialog, Smartphone as J, Cpu as Jn, ArrowLeft as Jr, Menu as Jt, Sparkles as K, KebabMenu, KeyValueList, Database as Kn, ArrowUpToLine as Kr, Mic as Kt, Thermometer as L, LIST_ROW, Label, LawnMowerHeroCard, LawnMowerInlineControl, LayeredSettingsForm, LightHeroCard, LightInlineControl, ExternalLink as Ln, LockHeroCard, LockInlineControl, LockPanel, LogStream, LoginForm, Battery as Lr, Music as Lt, Tractor as M, MEDIA_GRID, MINUTES_PER_DAY, MODE_COLOR, MaskShapeCanvas, MediaCard, MediaGrid, MediaPlayerHeroCard, MediaPlayerInlineControl, MediaPlayerPanel, Film as Mn, MobileDrawer, ModelPicker, MotionZonesSettings, Blinds as Mr, PawPrint as Mt, ToggleRight as N, NAVIGATION_DRIVE_INTERVAL_MS, NODE_COLOR_IDS, NatResultCard, NavigationPanel, NetworkLinkBadge, Feather as Nn, NodeMultiSelectField, NodePicker, NodeSelectField, NotificationTargetSelectField, NotificationTargetsField, Bird as Nr, Pause as Nt, TrendingDown as O, OCCUPANCY_KEY, OPTION_SELECT_SEARCH_MIN_OPTIONS, OfflineBadge, Footprints as On, OptionSelect, Bug as Or, Pipette as Ot, ToggleLeft as P, PAGE_SIZE_ALL, PHASE_CONFIG, PICKER_CHIP_LIMIT, PICKER_DEFAULT_GROUP_BY, PICKER_GROUP_BY_MODES, PICKER_GROUP_COLLAPSE_AT, PICKER_NONE_KEY, PICKER_NOUN_PLURAL, PICKER_NO_FILTERS, PICKER_PAGE_SIZE, PICKER_SEARCH_DEBOUNCE_MS, PICKER_WINDOW, PRIORITY, PTZOverlay, PageHeader, PageShell, PageSizeSelect, Pagination, PasswordInput, PhaseIcon, PipelineBuilder, PipelineRuntimeSelector, PipelineStep, PlaceholderChipField, PlayerOverlaysProvider, Fan as Pn, Popover, PopoverContent, PopoverRowAction, PopoverTrigger, Bike as Pr, PrimaryChildPicker, PrivacyMaskSettings, ProviderBadge, ProviderEntryPills, Package as Pt, PtzPanel, Siren as Q, CloudSun as Qn, AirVent as Qr, QrCode, Mail as Qt, QuantityValueInput, Target as R, RECONNECT_POLICY, RECORDED_PLAYBACK_MODES, RESOLUTION_BUCKET_MS, RIGHT, ROI_AREA_WARN_FRACTION, ROLE_DESCRIPTOR, ROOT_DETECTOR_STEP_ID, RadialGauge, Radio, RecordEntriesPanel, RecordedPlaybackProvider, RecordingPanel, ResponseLog, RetrainReviewBadge, Eraser as Rn, RoleDisplayDefaultsFromServer, RoleDisplayDefaultsProvider, RoleNodePill, RootModelSourceControl, RootSuppliedModelNote, BatteryWarning as Rr, Move as Rt, RunReport, RunningBadge, RunningStatusLine, Upload as S, SCENE_CAPTURE_VARIANTS, SECRET_MASK_PLACEHOLDER, SECRET_REVEAL_MS, SECTION_BODY, SECTION_CARD, SECTION_HEADER, SETTING_ROW, SETTING_ROW_LABEL, SETTING_ROW_STACK_BREAKPOINT, SETTING_ROW_VALUE, SETTING_ROW_VALUE_TEXT, SNAPSHOT_MEDIA_PATH, SPLIT_PANEL_OUTER, SPLIT_PANEL_SIDE, STACK_GAP, STATE_COLOR, STEP_DOCK_WIDTH_PX, SUBJECT_PATH_DWELL_EPS, SUBJECT_PATH_FULL_FRAME_COVERAGE, SUBJECT_PATH_MAX_POINTS, SceneMonitorEditor, ScopePicker, ScriptHeroCard, ScriptInlineControl, ScrollArea, SecretFieldControl, SecretRevealProvider, SectionCard, SectionToolbar, SectionedPage, SegmentedChoice, Select, SelectedChip, SemanticBadge, SendFrameToTrainingButton, SensorHeroCard, SensorInlineControl, SensorValueAtom, Separator, SettingRow, Sidebar, SidebarItem, Skeleton, SlideToggle, Slider, GripHorizontal as Sn, SnapshotButton, SortHeaderButton, Sparkline, Cat as Sr, Power as St, StableTabPanel, StatCard, StateTimeline, StateValuesStream, StatusBadge, StepDetailDock, StepInspectorPanel, StepModelRow, StepTimings, Stepper, StorageRecordsPanel, StreamBrokerSelector, StreamDebugOverlay, StreamPanel, Switch, SwitchHeroCard, SwitchInlineControl, SwitchPanel, SystemProvider, Type as T, TABLE_SCROLL_MAX_H, TEMPERATURE_SCALES, TEXT_FIELD_LABEL, TEXT_HINT, TEXT_METRIC, TEXT_SECTION_LABEL, TEXT_VALUE, TIMEZONES, Tabs, TabsContent, TabsList, TabsTrigger, TapToggle, Textarea, ThemeProvider, ThermostatHeroCard, ThermostatInlineControl, TimeSeriesChart, TimelineSlider, TimezoneSelector, Gauge as Tn, Tooltip, TooltipContent, TooltipTrigger, Camera as Tr, TrainingBaseModelPicker, TrainingCollectionPicker, Plus as Tt, Star as U, UNIT_PREFERENCES_NAMESPACE, UiTextProvider, UiTrans, DoorOpen as Un, UnitPicker, UnitPreferencesFromServer, UnitPreferencesProvider, Ban as Ur, MonitorPlay as Ut, Sun as V, VacuumHeroCard, VacuumInlineControl, ValueReadout, ValveHeroCard, ValveInlineControl, VersionBadge, ViewSwitch, Droplet as Vn, VodPlaybackProvider, BatteryFull as Vr, MousePointerClick as Vt, Square as W, WaterHeaterHeroCard, WaterHeaterInlineControl, WeatherHeroCard, WeatherInlineControl, WidgetMetricCard, WidgetPanel, WidgetRegistryProvider, WidgetSlot, DoorClosed as Wn, Baby as Wr, Minus as Wt, SkipForward as X, Cog as Xn, ArrowDownToLine as Xr, Maximize2 as Xt, SlidersHorizontal as Y, Copy as Yn, ArrowDown as Yr, Megaphone as Yt, SkipBack as Z, Cloud as Zn, ZoneEditingProvider, AlarmSmoke as Zr, MapPin as Zt, Vibrate as _, Heater as _n, ChevronRight as _r, Radio$1 as _t, Wrench as a, acceleratorLabel, acceleratorShortLabel, agentColumnKey, alignSeries, allDeviceTypeFilterOptions, Link2 as an, anchorNow, applyFleetQueryDefaults, applyPickerFilters, CircleX as ar, ariaSortForColumn, assignNodeColorId, Settings as at, axisTicks, User as b, badgeFor, binaryBatteryIsLow, bindsToModel, Hand as bn, booleanLabels, boundsInPicked, Check as br, QrCode$1 as bt, bucketTotals, buildColorByNodeId, buildDataRecordRows, buildPeerConnectionConfig, buildStepTreeFromSchema, buildSubjectPath, buildTimeSeriesModel, Wifi as c, catalogHasDraft, chartKeys, chartSeriesStyle, childEntityId, childListName, chipOverflow, chunk, clampMinute, classifyAddressScope, classifyCapability, classifySessionVerdict, clearPickerGroup, clusterRootModelIds, cn, colorIdForNode, columnsForContext, compareSrflxMappings, computePageButtons, consumableItemLevel, consumableLevelBarClass, consumableLevelLabel, consumableLevelVariant, containerChildToRef, countableDevices, coverHighlight, coverageLine, CirclePlus as cr, createAddonI18n, createSharedContext, createTheme, ScrollText as ct, currentAddonLanguage, cursorFractionFor, WifiLow as d, darkColors, dataRecordContents, dataRecordKey, dataRecordSearchText, dataRecordType, dataTableFacetGroups, dataTableFacets, decodeCustomWindow, decodeSeriesRef, defaultAxisSpec, defaultOfField, defaultSelectClusterRoots, defaultSingleClusterRoot, defaultTheme, defaultUiText, deriveDeviceKind, deriveWebrtcDebugStats, describeDeviceSelector, detectPlatform, deviceIntegrationResolver, deviceListStateOf, deviceMatchesFilter, deviceNameNouns, deviceOptionLabel, deviceRoleMeta, deviceRoleMetaOf, deviceTypeLabel, deviceTypeMeta, deviceTypeMetaOf, devicesToOptions, Info as dn, dockBox, CircleCheck as dr, draftFromQuery, Sailboat as dt, effectivePageSize, emptyDevicesWidens, emptySessionRun, LockOpen as en, encodeCustomWindow, encodeSeriesRef, energyBuckets, ensureMfHostInit, CloudRain as er, Shield as et, eventKindLabel, WifiHigh as f, filterDataTableRows, filterDeviceOptions, filterOccupancyLines, filterOptions as filterOptionSelectOptions, filterPickerDevices, finalizeSessionRun, findTimezone, flattenPickerGrouping, flattenPickerRows, fleetViewOf, Inbox as fn, foldDeviceName, formatChartBytes, formatChartNumber, formatChartValue, formatControlDateTime, formatDeviceName, formatLastSeen, formatNumeric, formatSettingValue, formatSpan, formatTimeLabel, CircleCheckBig as fr, freezeVerdict, Router as ft, fuzzyMatch, Volume2 as g, gapThresholdMs, getClassColor, getPhaseVisual, History as gn, ChevronUp as gr, groupAgentColumns, groupChildrenByLayout, groupDeviceSeries, groupPickerDevices, groupPickerDevicesBy, RefreshCw as gt, VolumeX as h, hardwareLabel, historyPageHref, House as hn, ChevronsDownUp as hr, RotateCcw as ht, hubOrigin, hubPath, hubUrl, hubWsUrl, humanDuration, humanizeName, humidifierTint, X as i, iconGlyphsFailed, iconGlyphsLoaded, ListChecks as in, indexDeviceNames, initialScrubState, insertAtSelection, Clapperboard as ir, isAbsentProvider, isByteUnit, isConsumableLevelField, isDataTableFilterActive, isDeviceNameStock, isDrawableSubjectPath, isFieldVisible, isGroupExpanded, isHistoryWindowId, isKeychainFieldValue, isModelScopedField, isPickableUnit, isRedactedSecret, isRefusal, isSecretField, isValueField, Share2 as it, TrainFront as j, Flame as jn, Bone as jr, Pencil as jt, TrendingUp as k, Flashlight as kn, Box as kr, Pin as kt, WifiZero as l, lawnMowerActivityMeta, lightColors, linePoints, LayoutGrid as ln, loadIconGlyphs, loadRemoteBundle, CirclePause as lr, Scan as lt, lucideExportName, WashingMachine as m, makeScrubBridge, mapRootDetectorPlacements, matchesCombo, mergeSecretForSubmit, metadataEntries, metadataString, minuteFromPointer, ImageOff as mn, mountAddonPage, mountPath, ChevronsUpDown as mr, RotateCw as mt, ZoomIn as n, nextGridPosition, nextReconnectAction, nextSort, nextSortDirection, nextTableSort, niceMax, niceRange, LoaderCircle as nn, nodeColorClass, nodeSoftBgClass, nodeTextColorClass, normalizeForSearch, normalizeLanguage, normalizeSelection, nounSpecFor, CloudFog as nr, ShieldCheck as nt, Workflow as o, occupancyFacets, occupancyLines, offListSelections, Lightbulb as on, openTopLayer, optionSearchText as optionSelectSearchText, CircleStop as or, orphanDeviceLabel, Server as ot, outsideBounds, overrideEntityIdFromLink, Waves as p, pageRows, pageSizeLabel, paginateRows, parentDetailOf, parseCapKey, parseCombo, parseConsumableLevel, parseIceCandidate, parsePickerGroupBy, parseProducerKey, parseRecordedServerMessage, partitionSelected as partitionOptionSelectSelected, partitionSuggested, pickerFacetFilterShown, pickerFacetKey, pickerFacetOptions, pickerFiltersActive, pickerGroupKey, pickerHiddenSelectedCount, pickerLocationKey, pickerQueryTokens, pickerRowFacts, pickerSearchText, pickerZoneFilterSuspended, pinnedStreamChoices, placePopover, Image as pn, CircleAlert as pr, preferenceForQuantity, previousWindow, projectSubjectPath, providerIcons, Route as pt, Snowflake as q, Crosshair as qn, ArrowRight as qr, MessageSquare as qt, quantityStoredUnit, quantityUnitChoices, Zap as r, readHistory, readHistoryPanels, readItemId, readStoredGroupBy, readUnitPreferences, reduceSessionRun, registerAddonBundle, renderMarkup, renderTagged, resetHubMountForTests, resetPickerFilters, resolveContainerPrimary, resolveControlAlign, resolveDeviceControl, resolveDeviceIntegration, resolveDeviceLabel, resolveDisplayIcon, resolveEffectiveDefaultModel, resolveEffectiveStepModel, resolveEventKindIcon, resolveHistoryWindow, resolveSearchable as resolveOptionSelectSearchable, resolveParentNames, resolvePrimaryChild, resolveSelectedDevices, resolveSensorDisplay, resolveStepDefaultModel, retrainReviewBadgeLook, List as rn, roiTooLarge, rootSourceState, routerBasename, Clock as rr, ShieldAlert as rt, runningDurationSince, runningStatusParts, Wind as s, sameDeviceName, sameLocationSuggestions, scrubReducer, searchSteps, secretDisplayValue, secretSubmitValue, segmentsFromChanges, selectPickerGroup, selectedDeviceOptions, serializeRecordedCommand, seriesRefId, settingsModelIdFor, sharedGapSpans, shiftPoints, shouldCommit, shouldEmit, shouldShowAddNewFooter, shouldShowUseQueryRow, shouldUseSingleNode, showsNoCamerasHint, Leaf as sn, snapMinute, sortRows, sortRowsByColumn, CircleQuestionMark as sr, Search as st, stackBuckets, stackSeries, stateAt, stateRow, stateStyle, statusIcons, statusLine, stepFieldDomId, stepHasModelForFormat, stepLocalFields, stepModelOptions, storedToPicked, stripDeviceParentPrefix, stripParentNamePrefix, subjectPathSampleFromBox, subjectPathSvgPoints, summarizeHubCandidates, swatchFillClass, swatchLineClass, ZoomOut as t, tabForSelector, themeToCss, themeToRootCss, timeInState, LocateFixed as tn, toStationaryOverlayBox, toggleDataTableFacet, toggleDataTableGroupFacet, togglePickerDevice, togglePickerKey, CloudLightning as tr, trainingRefusalText, translateAddonKey, trpc, ShieldOff as tt, typeLabel, typedToStored, WifiOff as u, uiLibraryVersion, Laugh as un, unitAxes, CircleDot as ur, useAccessoriesGetStatus, useAccessoriesSetChildHidden, useAccountUnitPreferences, useActionSourceListActions, useActionSourceRunAction, useActionSourceStopAction, useActionsCreate, useActionsDelete, useActionsGet, useActionsGetLinks, useActionsGetTraces, useActionsList, useActionsListForCamera, useActionsRun, useActionsSetLinks, useActionsStop, useActionsUpdate, useAddonPagesListPages, useAddonSettingsGetDeclaredSettingsKeys, useAddonSettingsGetDeviceSettings, useAddonSettingsGetGlobalSettings, useAddonSettingsGetIntegrationFormSchema, useAddonSettingsGetIntegrationSettings, useAddonSettingsUnsetStoredSettingsKeys, useAddonSettingsUpdateDeviceSettings, useAddonSettingsUpdateGlobalSettings, useAddonT, useAddonWidgetsListWidgets, useAddonsApplyAutoUpdateToAll, useAddonsCancelJob, useAddonsCustom, useAddonsForceRefresh, useAddonsGetAddonAutoUpdate, useAddonsGetAutoUpdateSettings, useAddonsGetJob, useAddonsGetLastRestart, useAddonsGetLogs, useAddonsGetPackageDocs, useAddonsGetVersions, useAddonsInstallPackage, useAddonsList, useAddonsListCapabilityProviders, useAddonsListFrameworkPackages, useAddonsListInstallations, useAddonsListJobs, useAddonsListPackages, useAddonsListUpdates, useAddonsOnAddonLogs, useAddonsReloadPackages, useAddonsRestartAddon, useAddonsRestartServer, useAddonsRetryLoad, useAddonsRollbackPackage, useAddonsSearchAvailable, useAddonsSetAddonAutoUpdate, useAddonsSetAutoUpdateSettings, useAddonsSetCapabilityProviderEnabled, useAddonsStartJob, useAddonsUninstallPackage, useAddonsUpdatePackage, useAirQualitySensorGetStatus, useAlarmPanelArm, useAlarmPanelDisarm, useAlarmPanelGetStatus, useAlarmPanelTrigger, useAlert, useAlertsDismiss, useAlertsEmit, useAlertsGetUnreadCount, useAlertsList, useAlertsMarkAllRead, useAlertsMarkRead, useAlertsUpdate, useAllWidgets, useAmbientLightSensorGetStatus, useAudioAnalysisApplyDeviceSettingsPatch, useAudioAnalysisGetDeviceLiveContribution, useAudioAnalysisGetDeviceSettingsContribution, useAudioAnalysisResolveDeviceSettings, useAudioAnalyzerAnalyseChunk, useAudioAnalyzerAttachDevice, useAudioAnalyzerClassify, useAudioAnalyzerDetachDevice, useAudioAnalyzerDispose, useAudioAnalyzerIsReady, useAudioAnalyzerReprobeAudioEngine, useAudioCodecCanHandle, useAudioCodecCloseSession, useAudioCodecCreateDecodeSession, useAudioCodecCreateEncodeSession, useAudioCodecFlushEncode, useAudioCodecListActiveSessions, useAudioCodecListSupportedCodecs, useAudioCodecPullEncoded, useAudioCodecPullPcm, useAudioCodecPushEncodedFrame, useAudioCodecPushPcm, useAudioMetricsGetCurrentSnapshot, useAudioMetricsGetHistory, useAutomationControlDisable, useAutomationControlEnable, useAutomationControlGetStatus, useAutomationControlTrigger, useBackupCancel, useBackupCheckBackupKey, useBackupDelete, useBackupDeleteSchedule, useBackupDisableEncryption, useBackupGetEncryption, useBackupGetEntries, useBackupList, useBackupListArchives, useBackupListAvailableDatabases, useBackupListDestinations, useBackupListLocations, useBackupListRuns, useBackupListSchedules, useBackupPreviewSchedule, useBackupRestore, useBackupSetupEncryption, useBackupTrigger, useBackupUpsertDestinationPolicy, useBackupUpsertSchedule, useBatteryGetStatus, useBatteryWakeForStream, useBinaryGetStatus, useBrightnessGetStatus, useBrightnessSetBrightness, useBrokerAdd, useBrokerGet, useBrokerGetBrokerConfig, useBrokerGetSettings, useBrokerGetSettingsSchema, useBrokerGetState, useBrokerGetStatus, useBrokerList, useBrokerListProviders, useBrokerPickerSlot, useBrokerPublish, useBrokerRemove, useBrokerSetSettings, useBrokerSubscribe, useBrokerTestConnection, useBrokerTestSettings, useBrokerUnsubscribe, useButtonPress, useCalendarsGetPreferences, useCalendarsListCalendars, useCalendarsListEvents, useCalendarsSetCalendarPreference, useCameraCredentialsGetCredentials, useCameraCredentialsGetStatus, useCameraGridLayoutApplyDeviceSettingsPatch, useCameraGridLayoutGetDeviceLiveContribution, useCameraGridLayoutGetDeviceSettingsContribution, useCameraGridLayoutGetLayout, useCameraGridLayoutSaveLayout, useCameraPipelineConfigApplyDeviceSettingsPatch, useCameraPipelineConfigGetDeviceLiveContribution, useCameraPipelineConfigGetDeviceSettingsContribution, useCameraStreamsGetBrokerStreams, useCameraStreamsGetCameraStreams, useCameraStreamsGetProfileRtspEntries, useCameraStreamsGetRtspEntries, useCameraStreamsPickStream, useCapabilityPresence, useCarbonMonoxideGetStatus, useClassPainter, useClimateControlGetStatus, useClimateControlSetFanMode, useClimateControlSetMode, useClimateControlSetPreset, useClimateControlSetSwingHorizontal, useClimateControlSetSwingVertical, useClimateControlSetTarget, useClimateControlSetTargetHumidity, useClimateControlSetTargetRange, useClusterNodes, useClusterTopology, useColorGetStatus, useColorSetColor, useConfirm, useConnectionTestDescribeTest, useConnectionTestTestSettings, useConnectivityGetStatus, useConsumablesGetStatus, useConsumablesReset, useContactGetStatus, useContainerChildren, useControlGetStatus, useControlSetValue, useCoreBlocksCompile, useCoreBlocksCreate, useCoreBlocksCreateComposition, useCoreBlocksDelete, useCoreBlocksGet, useCoreBlocksGetAutomationRunState, useCoreBlocksGetBlockSettings, useCoreBlocksGetComposition, useCoreBlocksGetCustomization, useCoreBlocksGetTraces, useCoreBlocksGetTypeDefs, useCoreBlocksList, useCoreBlocksListComposableCaps, useCoreBlocksListCompositions, useCoreBlocksMigrateRawSecrets, useCoreBlocksReportAutomationRun, useCoreBlocksRestart, useCoreBlocksSetEnabled, useCoreBlocksUpdate, useCoreBlocksUpdateBlockSettings, useCoreBlocksUpdateComposition, useCoreBlocksValidateComposition, useCoverClose, useCoverGetStatus, useCoverOpen, useCoverSetPosition, useCoverSetTiltPosition, useCoverStop, useCustomFieldRenderer, useDataTableFilter, useDayNightGetOptions, useDayNightGetStatus, useDayNightSetSettings, useDebouncedString, useDecoderGetInfo, useDecoderReprobeHwaccel, useDetectionPipelineApplyDeviceSettingsPatch, useDetectionPipelineGetDeviceLiveContribution, useDetectionPipelineGetDeviceSettingsContribution, useDevShell, useDevice, useDeviceAdminLink, useDeviceAdminLinkGetAdminLink, useDeviceAdoptionAdopt, useDeviceAdoptionGetCandidate, useDeviceAdoptionGetStatus, useDeviceAdoptionListCandidateFilters, useDeviceAdoptionListCandidates, useDeviceAdoptionRefresh, useDeviceAdoptionRelease, useDeviceAdoptionResync, useDeviceAutotrack, useDeviceBattery, useDeviceCapSlice, useDeviceCapability, useDeviceCredentialsDeleteDeviceCredential, useDeviceCredentialsGetDeviceCaStatus, useDeviceCredentialsGetDeviceCertificateSettings, useDeviceCredentialsListDeviceCredentials, useDeviceCredentialsRenameDeviceCredential, useDeviceCredentialsRevokeDeviceCredential, useDeviceCredentialsSetDeviceCertificateSettings, useDeviceCredentialsStartEnrollment, useDeviceDetections, useDeviceDiscoveryAdoptDevice, useDeviceDiscoveryGetStatus, useDeviceDiscoveryListDiscovered, useDeviceDiscoveryRefreshDiscovery, useDeviceDiscoveryReleaseDevice, useDeviceExportApplyDeviceSettingsPatch, useDeviceExportExposeDevice, useDeviceExportExposeEntity, useDeviceExportGetDeviceLiveContribution, useDeviceExportGetDeviceSettingsContribution, useDeviceExportGetStatus, useDeviceExportListExposedDevices, useDeviceExportListExposedEntities, useDeviceExportListSupportedDeviceKinds, useDeviceExportListSupportedEntityKinds, useDeviceExportUnexposeDevice, useDeviceExportUnexposeEntity, useDeviceExtensionListCandidates, useDeviceExtensionListSlots, useDeviceExtensionListSources, useDeviceExtensionSetSlot, useDeviceHistoryDeclareSeries, useDeviceHistoryDeleteOrphanSeries, useDeviceHistoryGetDeviceEnabled, useDeviceHistoryGetStatus, useDeviceHistoryListNodeSeries, useDeviceHistoryListOrphanSeries, useDeviceHistoryListSeries, useDeviceHistoryQuery, useDeviceHistoryQueryMany, useDeviceHistoryQueryNode, useDeviceHistoryRecord, useDeviceHistoryRecordBuckets, useDeviceHistorySetDeviceEnabled, useDeviceId, useDeviceLabel, useDeviceLabelById, useDeviceListPageSize, useDeviceManagerAddLocation, useDeviceManagerAdoptDevice, useDeviceManagerAdoptionAdopt, useDeviceManagerAdoptionCancelJob, useDeviceManagerAdoptionListCandidateFilters, useDeviceManagerAdoptionListCandidates, useDeviceManagerAdoptionListJobs, useDeviceManagerAdoptionRefresh, useDeviceManagerAdoptionRelease, useDeviceManagerAdoptionResync, useDeviceManagerAdoptionStartJob, useDeviceManagerAllocateDeviceId, useDeviceManagerApplyInitialMeta, useDeviceManagerCleanupDeletedDevicesData, useDeviceManagerCreateDevice, useDeviceManagerDisable, useDeviceManagerDiscoverAllProviders, useDeviceManagerDiscoverDevices, useDeviceManagerDiscoverProvider, useDeviceManagerDiscoveryProviders, useDeviceManagerEnable, useDeviceManagerGetAllBindings, useDeviceManagerGetBindings, useDeviceManagerGetBindingsBatch, useDeviceManagerGetChildren, useDeviceManagerGetChildrenBatch, useDeviceManagerGetConfigSchema, useDeviceManagerGetCreationSchema, useDeviceManagerGetDevice, useDeviceManagerGetDeviceAggregate, useDeviceManagerGetDeviceLiveInfoAggregate, useDeviceManagerGetDeviceSettingsAggregate, useDeviceManagerGetDeviceStatusAggregate, useDeviceManagerGetDeviceStatusAggregateBatch, useDeviceManagerGetLinkedDevices, useDeviceManagerGetLinkedDevicesBatch, useDeviceManagerGetRoleDisplayDefaults, useDeviceManagerGetSettingsSchema, useDeviceManagerGetStreamProfileMap, useDeviceManagerGetStreamSources, useDeviceManagerGetWireableFields, useDeviceManagerGetWrapperActivation, useDeviceManagerListAll, useDeviceManagerListBindableCapsForDeviceType, useDeviceManagerListDeletedSince, useDeviceManagerListDeviceIdsByCaps, useDeviceManagerListLocationDescriptions, useDeviceManagerListLocationIcons, useDeviceManagerListLocations, useDeviceManagerListPersistedByAddon, useDeviceManagerListSiteZones, useDeviceManagerListWrappersForCap, useDeviceManagerLoadConfig, useDeviceManagerLoadMeta, useDeviceManagerLoadRuntimeState, useDeviceManagerMigrateDevice, useDeviceManagerPersistConfig, useDeviceManagerProbeStreams, useDeviceManagerProviderCreationType, useDeviceManagerProviderDiscoveryParamsSchema, useDeviceManagerRegisterDevice, useDeviceManagerRemove, useDeviceManagerRemoveByIntegration, useDeviceManagerRemoveDevice, useDeviceManagerRemoveLocation, useDeviceManagerRemoveSiteZone, useDeviceManagerRenameLocation, useDeviceManagerRenameSiteZone, useDeviceManagerRunDeviceAction, useDeviceManagerSetChildLayout, useDeviceManagerSetDisabled, useDeviceManagerSetDisplay, useDeviceManagerSetIntegrationId, useDeviceManagerSetLinkDeviceId, useDeviceManagerSetLocation, useDeviceManagerSetLocationDescription, useDeviceManagerSetLocationIcon, useDeviceManagerSetLocationZone, useDeviceManagerSetMetadata, useDeviceManagerSetName, useDeviceManagerSetPrimaryChildEntityId, useDeviceManagerSetRole, useDeviceManagerSetRoleDisplayDefaults, useDeviceManagerSetSiteZone, useDeviceManagerSetStreamProfileMap, useDeviceManagerSetType, useDeviceManagerSetWrapperActive, useDeviceManagerTestCreationField, useDeviceManagerTestField, useDeviceManagerUpdateConfig, useDeviceManagerUpdateDeviceField, useDeviceManagerUpdateDeviceFieldsBatch, useDeviceNameIndex, useDeviceNameNouns, useDeviceNetworkLink, useDeviceOpsGetConfigEntries, useDeviceOpsGetRawState, useDeviceOpsGetSettingsSchema, useDeviceOpsGetStreamSources, useDeviceOpsRemoveDevice, useDeviceOpsRunAction, useDeviceOpsSetConfig, useDeviceProviderAdoptDiscoveredDevice, useDeviceProviderClassifyDiscoveryHits, useDeviceProviderCreateDevice, useDeviceProviderDiscoverDevices, useDeviceProviderGetChildCreationSchema, useDeviceProviderGetDevices, useDeviceProviderGetDiscoveryModes, useDeviceProviderGetDiscoveryParamsSchema, useDeviceProviderGetManualCreationType, useDeviceProviderGetStatus, useDeviceProviderReloadDevice, useDeviceProviderStart, useDeviceProviderStop, useDeviceProviderSupportsDiscovery, useDeviceProviderSupportsManualCreation, useDeviceProviderTestCreationField, useDeviceProxy, useDeviceQuickDetailOpen, useDeviceRunsGetCurrentRun, useDeviceRunsGetRun, useDeviceRunsListRuns, useDeviceSeriesList, useDeviceSnapshot, useDeviceSnapshotImage, useDeviceState, useDeviceStateClaimFields, useDeviceStateGetAllSnapshots, useDeviceStateGetCapSlice, useDeviceStateGetNativeCapSlice, useDeviceStateGetSnapshot, useDeviceStateListClaims, useDeviceStatePatchOwnedFields, useDeviceStateReleaseClaim, useDeviceStateSetCapSlice, useDeviceStateSlice, useDeviceStatusGetStatus, useDeviceWebrtc, useDevices, useDiscoveredOptions, useDishwasherGetOptions, useDishwasherGetStatus, useDishwasherPause, useDishwasherResume, useDishwasherSetChildLock, useDishwasherSetExtraDry, useDishwasherSetHalfLoad, useDishwasherSetHygienePlus, useDishwasherSetIntensiveZone, useDishwasherSetOption, useDishwasherSetPower, useDishwasherSetProgram, useDishwasherSetVarioSpeedPlus, useDishwasherStart, useDishwasherStop, useDisplayIconResolver, useDisplayPaletteGetPalette, useDisplayPaletteListPresets, useDisplayPaletteSetPalette, useDisplayPaletteView, useDoNotDisturbGetStatus, useDoNotDisturbSetEnabled, useDoorbellEvents, useDoorbellGetStatus, useEnumSensorGetStatus, useEventEmitterGetStatus, useEventInvalidation, useEventStreamLatest, useEventStreamMap, useFaceGalleryAssignFace, useFaceGalleryAssignFaces, useFaceGalleryAuditIdentitySamples, useFaceGalleryCreateIdentity, useFaceGalleryDeleteFace, useFaceGalleryDeleteIdentity, useFaceGalleryGetFaceByTrack, useFaceGalleryGetFaceMedia, useFaceGalleryListIdentities, useFaceGalleryListIdentitySamples, useFaceGalleryListRecentFaces, useFaceGalleryRemoveSample, useFaceGalleryRenameIdentity, useFaceGallerySuggestFaceClusters, useFaceGalleryUnassignFace, useFaceGalleryUnassignFaces, useFanControlGetStatus, useFanControlSetDirection, useFanControlSetOscillating, useFanControlSetPercentage, useFanControlSetPreset, useFanPresetsApplyPreset, useFanPresetsCapturePreset, useFanPresetsGetPresets, useFanPresetsSetPresets, useFeatureProbeGetStatus, useFloodGetStatus, useGasGetStatus, useGroupActiveGetStatus, useGroupCommandsGetStatus, useGroupStatusGetStatus, useHeatingValveGetStatus, useHistoryPanels, useHistoryReader, useHistoryReads, useHotkey, useHumidifierGetStatus, useHumidifierSetMode, useHumidifierSetOn, useHumidifierSetTargetHumidity, useHumiditySensorGetStatus, useIconGlyphsVersion, useImageGetStatus, useImageSettingsGetOptions, useImageSettingsGetStatus, useImageSettingsSetSettings, useIntegrationsCreate, useIntegrationsDelete, useIntegrationsGet, useIntegrationsGetAvailableTypes, useIntegrationsGetByAddonId, useIntegrationsGetSettings, useIntegrationsList, useIntegrationsSetSettings, useIntegrationsTestConnection, useIntegrationsUpdate, useIntercomEndTalkSession, useIntercomGetStatus, useIntercomHandleAnswer, useIntercomPushTalkAudio, useIntercomStartSession, useIntercomStartTalkSession, useIntercomStopSession, useIrTransmitterGetInfo, useIrTransmitterSend, useIsMidWidth, useIsMobile, useItemFormUrl, useKeychainAdminAcknowledgeReset, useKeychainAdminDeleteOrphans, useKeychainAdminDownloadRecoveryKey, useKeychainAdminImportSecret, useKeychainAdminListAudit, useKeychainAdminListSecrets, useKeychainAdminPurgeRetiredKeys, useKeychainAdminResetKeychain, useKeychainAdminResetReport, useKeychainAdminReveal, useKeychainAdminRotateMasterKey, useKeychainAdminSetSystemSecret, useKeychainAdminStatus, useLawnMowerControlDock, useLawnMowerControlGetStatus, useLawnMowerControlPause, useLawnMowerControlStartMowing, useLiveBuffer, useLiveEvent, useLlmCancel, useLlmDeleteModel, useLlmDeleteProfile, useLlmGenerate, useLlmGenerateVision, useLlmGetDefaults, useLlmGetRuntimeStatus, useLlmGetUsage, useLlmInstallModel, useLlmListModelCatalog, useLlmListModels, useLlmListNodeModels, useLlmListProfileKinds, useLlmListProfiles, useLlmListRuntimeNodes, useLlmMigrateRawSecrets, useLlmResolveModelRef, useLlmSetDefault, useLlmStartRuntime, useLlmStopRuntime, useLlmTestProfile, useLlmUpsertProfile, useLocalNetworkAddCustomAddress, useLocalNetworkDownloadCa, useLocalNetworkGetAddresses, useLocalNetworkGetAllowedAddresses, useLocalNetworkGetConnectionEndpoints, useLocalNetworkGetHubAddresses, useLocalNetworkGetNotificationEndpoint, useLocalNetworkGetPreferred, useLocalNetworkGetScanSubnets, useLocalNetworkGetTlsStatus, useLocalNetworkGetViewerEndpoints, useLocalNetworkList, useLocalNetworkRegenerateCertificate, useLocalNetworkRemoveCustomAddress, useLocalNetworkResetAllowlistToBestMatch, useLocalNetworkRevertToGeneratedCertificate, useLocalNetworkScanNetwork, useLocalNetworkSetAddressRole, useLocalNetworkSetAllowedAddresses, useLocalNetworkSetNotificationEndpoint, useLocalNetworkSetScanSubnets, useLocalNetworkSetViewerEndpoints, useLocalNetworkUploadCertificate, useLocalNetworkUseStoredUploadedCertificate, useLockControlGetStatus, useLockControlLock, useLockControlOpen, useLockControlUnlock, useLockDoorSensor, useMediaPlayerGetStatus, useMediaPlayerNext, useMediaPlayerPause, useMediaPlayerPlay, useMediaPlayerPlayMedia, useMediaPlayerPrevious, useMediaPlayerSeek, useMediaPlayerSelectSource, useMediaPlayerSetMute, useMediaPlayerSetRepeat, useMediaPlayerSetShuffle, useMediaPlayerSetVolume, useMediaPlayerStop, useMeshNetworkGetStatus, useMeshNetworkJoin, useMeshNetworkLeave, useMeshNetworkListPeers, useMeshNetworkLogout, useMeshNetworkStartLogin, useMeshNetworkTestConnection, useMeterGetStatus, useMetricsProviderCollectSnapshot, useMetricsProviderGetAddonStats, useMetricsProviderGetCached, useMetricsProviderGetCpuTemperature, useMetricsProviderGetCurrent, useMetricsProviderGetDiskSpace, useMetricsProviderGetGpuInfo, useMetricsProviderGetLoadSeries, useMetricsProviderGetProcessStats, useMetricsProviderListAddonInstances, useMetricsProviderListNodeProcesses, useMotionDetectionAnalyze, useMotionDetectionApplyDeviceSettingsPatch, useMotionDetectionGetDeviceLiveContribution, useMotionDetectionGetDeviceSettingsContribution, useMotionDetectionRemoveCamera, useMotionDetectionReset, useMotionGetStatus, useMotionIsDetected, useMotionTriggerGetStatus, useMotionTriggerSetMotionTrigger, useMotionZonesGetOptions, useMotionZonesGetStatus, useMotionZonesSetZone, useMqttBrokerAddBroker, useMqttBrokerGetBrokerConfig, useMqttBrokerGetStatus, useMqttBrokerListBrokers, useMqttBrokerRemoveBroker, useMqttBrokerStartEmbeddedBroker, useMqttBrokerStopEmbeddedBroker, useMqttBrokerTestConnection, useNativeObjectDetectionGetOptions, useNativeObjectDetectionGetStatus, useNativeObjectDetectionSetEnabled, useNativeObjectDetectionSetSettings, useNavigation, useNavigationGetFeatures, useNavigationGetStatus, useNavigationGoToPoint, useNavigationListActions, useNavigationMove, useNavigationPlaySound, useNavigationRunAction, useNavigationSetLightLevel, useNavigationSetLightMode, useNavigationSetLightOn, useNavigationStop, useNetworkAccessGetEndpoint, useNetworkAccessGetStatus, useNetworkAccessListEndpoints, useNetworkAccessStart, useNetworkAccessStop, useNetworkLinkGetStatus, useNetworkQualityGetAllStats, useNetworkQualityGetDeviceStats, useNetworkQualityReportClientStats, useNodesClusterAddonStatus, useNodesDeployAddon, useNodesDirectory, useNodesExecuteQuery, useNodesGetCapUsageGraph, useNodesGetNodeAddons, useNodesRenameNode, useNodesRestartAddon, useNodesRestartNode, useNodesRestartProcess, useNodesSetProcessLogLevel, useNodesShutdownNode, useNodesTopology, useNodesUndeployAddon, useNotificationOutputDeleteTarget, useNotificationOutputDiscoverTargets, useNotificationOutputGetTarget, useNotificationOutputListTargetKinds, useNotificationOutputListTargets, useNotificationOutputProbeTargetConfig, useNotificationOutputSend, useNotificationOutputSetTargetEnabled, useNotificationOutputTestTarget, useNotificationOutputUpsertTarget, useNotificationRulesActivateAlarmProfile, useNotificationRulesCancelSnooze, useNotificationRulesCreateAlarmProfile, useNotificationRulesCreateRule, useNotificationRulesCreateSequence, useNotificationRulesCreateSnooze, useNotificationRulesDeleteAlarmProfile, useNotificationRulesDeleteRule, useNotificationRulesDeleteSequence, useNotificationRulesGetAlarmConfig, useNotificationRulesGetAlarmSensors, useNotificationRulesGetClipRetentionAsks, useNotificationRulesGetConditionCatalog, useNotificationRulesGetHistory, useNotificationRulesGetRule, useNotificationRulesGetRuleLastRuns, useNotificationRulesGetSequence, useNotificationRulesGetTemplateCatalog, useNotificationRulesListDeviceMutes, useNotificationRulesListRules, useNotificationRulesListSequences, useNotificationRulesListSnoozes, useNotificationRulesPreviewStateSummary, useNotificationRulesPreviewTemplate, useNotificationRulesRenameAlarmProfile, useNotificationRulesResolveArtifactUrl, useNotificationRulesSetAlarmConfig, useNotificationRulesSetDeviceMuted, useNotificationRulesSetRuleEnabled, useNotificationRulesTestRule, useNotificationRulesUpdateRule, useNotificationRulesUpdateSequence, useNotifierCancel, useNotifierGetStatus, useNotifierSend, useNumericSensorGetStatus, useOidcConnectionsConnectionFormSchema, useOidcConnectionsCreateConnection, useOidcConnectionsDeleteConnection, useOidcConnectionsListConnections, useOidcConnectionsUpdateConnection, useOptimisticSlice, useOptionalSystem, useOptionalWidgetRegistry, useOsdGetStatus, useOsdManagerClearSlotBinding, useOsdManagerCopyDeviceConfiguration, useOsdManagerDeleteTemplate, useOsdManagerGetConditionSupport, useOsdManagerGetDeviceOsd, useOsdManagerGetSourceCatalog, useOsdManagerListTemplates, useOsdManagerPreviewSlot, useOsdManagerRenderDevice, useOsdManagerSetSlotBinding, useOsdManagerSetSlotCameraEnabled, useOsdManagerUpsertTemplate, useOsdSetOverlay, usePTZ, usePersistedDisclosure, usePersistedPageSize, usePetFeederCallPet, usePetFeederCancelFeed, usePetFeederFeed, usePetFeederGetStatus, usePetFeederMarkFoodReplenished, usePetFeederPlaySound, usePetFeederResetDesiccant, usePetFeederSetChildLock, usePetFeederSetFeedSound, usePetFeederSetIndicatorLight, usePetFeederSetVolume, usePetFountainGetStatus, usePetFountainResetDailyConsumption, usePetFountainSetPump, usePetFountainSetPumpInterval, usePetFountainSetPumpOffMinutes, usePetFountainSetPumpOnMinutes, usePickerSiteZones, usePipelineAnalyticsAddRetrainFrameFromRecording, usePipelineAnalyticsAddRetrainFramesToCollection, usePipelineAnalyticsApplyDeviceSettingsPatch, usePipelineAnalyticsBackfillRetrainOrigins, usePipelineAnalyticsCancelRelocateMedia, usePipelineAnalyticsCancelStorageMigrationMove, usePipelineAnalyticsClearTrackRelation, usePipelineAnalyticsClearTracks, usePipelineAnalyticsCompleteRetrainTrack, usePipelineAnalyticsCountRelocatableMedia, usePipelineAnalyticsCountUnstampedEventMedia, usePipelineAnalyticsCreateRetrainCollection, usePipelineAnalyticsDeleteDeviceEvents, usePipelineAnalyticsDeleteRetrainCollection, usePipelineAnalyticsDeleteTracks, usePipelineAnalyticsDeselectRetrainFrame, usePipelineAnalyticsGetActiveTracks, usePipelineAnalyticsGetAudioEvents, usePipelineAnalyticsGetDeviceLiveContribution, usePipelineAnalyticsGetDeviceSettingsContribution, usePipelineAnalyticsGetEventDensity, usePipelineAnalyticsGetEventDensityBatch, usePipelineAnalyticsGetEventMedia, usePipelineAnalyticsGetEventMediaFootprintByKind, usePipelineAnalyticsGetEventStoreFootprint, usePipelineAnalyticsGetKeyEvents, usePipelineAnalyticsGetKeyEventsBatch, usePipelineAnalyticsGetMediaReclaimStatus, usePipelineAnalyticsGetMotionEvents, usePipelineAnalyticsGetObjectEmbeddingRebuildStatus, usePipelineAnalyticsGetObjectEvents, usePipelineAnalyticsGetRetrainCorpusKpi, usePipelineAnalyticsGetRetrainExportUrl, usePipelineAnalyticsGetRetrainFrameImage, usePipelineAnalyticsGetSensorEvents, usePipelineAnalyticsGetStorageMigrationMoveStatus, usePipelineAnalyticsGetTrack, usePipelineAnalyticsGetTrackMedia, usePipelineAnalyticsGetTrainingExportSummary, usePipelineAnalyticsGetTrainingExportUrl, usePipelineAnalyticsListArchivedDebugNotes, usePipelineAnalyticsListBirthDecisions, usePipelineAnalyticsListEventKinds, usePipelineAnalyticsListEventKindsBatch, usePipelineAnalyticsListEventMedia, usePipelineAnalyticsListOpsLog, usePipelineAnalyticsListRecentTracks, usePipelineAnalyticsListRelocateMediaJobs, usePipelineAnalyticsListRetrainAnnotations, usePipelineAnalyticsListRetrainAssistProfiles, usePipelineAnalyticsListRetrainCollectionFrames, usePipelineAnalyticsListRetrainCollections, usePipelineAnalyticsListRetrainCorpusPage, usePipelineAnalyticsListRetrainFrames, usePipelineAnalyticsListRetrainStaging, usePipelineAnalyticsListTrackMedia, usePipelineAnalyticsListTrackRelations, usePipelineAnalyticsListTracks, usePipelineAnalyticsOfferRetrainArchive, usePipelineAnalyticsOwnersWithMedia, usePipelineAnalyticsPauseForStorageMigration, usePipelineAnalyticsProposeRetrainAnnotations, usePipelineAnalyticsProposeRetrainAnnotationsWithLlm, usePipelineAnalyticsPruneEvents, usePipelineAnalyticsPruneEventsBefore, usePipelineAnalyticsPruneTracksBefore, usePipelineAnalyticsReadLongTermSeries, usePipelineAnalyticsRebuildObjectEmbeddings, usePipelineAnalyticsReclaimDebugMedia, usePipelineAnalyticsReconcileFromDisk, usePipelineAnalyticsRefreshStorageLocationsForMigration, usePipelineAnalyticsRelocateMedia, usePipelineAnalyticsRemoveRetrainFrameFromCollection, usePipelineAnalyticsRenameRetrainCollection, usePipelineAnalyticsResolveRetrainTrainingCorpus, usePipelineAnalyticsRestageRetrainTrack, usePipelineAnalyticsResumeForStorageMigration, usePipelineAnalyticsSaveRetrainAnnotations, usePipelineAnalyticsSearchObjectEvents, usePipelineAnalyticsSelectRetrainFrames, usePipelineAnalyticsSetRetrainFrameComplete, usePipelineAnalyticsSetTrackFlags, usePipelineAnalyticsSetTrackPurity, usePipelineAnalyticsSetTrackRelation, usePipelineAnalyticsStartStorageMigrationMove, usePipelineAnalyticsWipeAllAnalytics, usePipelineAnalyticsWipeObjectEmbeddings, usePipelineAnalyticsWriteRetrainArchive, usePipelineExecutorCacheFrameInPool, usePipelineExecutorDeleteModel, usePipelineExecutorDownloadModel, usePipelineExecutorGetAddonModels, usePipelineExecutorGetAudioCapabilities, usePipelineExecutorGetAvailableEngines, usePipelineExecutorGetCapabilities, usePipelineExecutorGetDetectionConfigSchema, usePipelineExecutorGetEffectiveTuning, usePipelineExecutorGetEngineProvisioning, usePipelineExecutorGetInferenceDeviceHealth, usePipelineExecutorGetOrchestratorConfigSchema, usePipelineExecutorGetReferenceAudio, usePipelineExecutorGetReferenceAudioFiles, usePipelineExecutorGetReferenceImage, usePipelineExecutorGetSchema, usePipelineExecutorGetSelectedEngine, usePipelineExecutorGetVideoPipelineSteps, usePipelineExecutorInferCached, usePipelineExecutorKillEngine, usePipelineExecutorListLoadedEngines, usePipelineExecutorListReferenceImages, usePipelineExecutorRearmInferenceDevice, usePipelineExecutorRunAudioTest, usePipelineExecutorRunPipeline, usePipelineExecutorRunPipelineBatch, usePipelineExecutorSetVideoPipelineSteps, usePipelineExecutorSpinEngine, usePipelineExecutorUncacheFrame, usePipelineExecutorValidatePipeline, usePipelineOrchestratorAbortNodeBenchmark, usePipelineOrchestratorApplyAutoTune, usePipelineOrchestratorApplyDeviceSettingsPatch, usePipelineOrchestratorAssignAudio, usePipelineOrchestratorAssignPipeline, usePipelineOrchestratorDeleteNodeBenchmarkResult, usePipelineOrchestratorForgetInferenceDevice, usePipelineOrchestratorGetAgentLoad, usePipelineOrchestratorGetAgentSettings, usePipelineOrchestratorGetAudioAssignment, usePipelineOrchestratorGetAudioAssignments, usePipelineOrchestratorGetAudioNodeLoad, usePipelineOrchestratorGetCameraDetectionSource, usePipelineOrchestratorGetCameraMetrics, usePipelineOrchestratorGetCameraSettings, usePipelineOrchestratorGetCameraStatus, usePipelineOrchestratorGetCameraStatuses, usePipelineOrchestratorGetCameraSwitches, usePipelineOrchestratorGetCapabilityBindings, usePipelineOrchestratorGetClusterModelChoice, usePipelineOrchestratorGetDeviceLiveContribution, usePipelineOrchestratorGetDeviceSettingsContribution, usePipelineOrchestratorGetEffectiveShares, usePipelineOrchestratorGetGlobalMetrics, usePipelineOrchestratorGetIngestOwner, usePipelineOrchestratorGetNodeBenchmarkCandidates, usePipelineOrchestratorGetNodeBenchmarkPreflight, usePipelineOrchestratorGetNodeBenchmarkStatus, usePipelineOrchestratorGetNodeInferenceDevices, usePipelineOrchestratorGetPipelineAssignment, usePipelineOrchestratorGetPipelineAssignments, usePipelineOrchestratorGetPipelineDevicePin, usePipelineOrchestratorGetPlacementStats, usePipelineOrchestratorGetReconcileFromDiskStatus, usePipelineOrchestratorListAgentSettings, usePipelineOrchestratorListNodeBenchmarkResults, usePipelineOrchestratorPauseForStorageMigration, usePipelineOrchestratorPlanAutoTune, usePipelineOrchestratorRebalance, usePipelineOrchestratorReconcileFromDisk, usePipelineOrchestratorRemoveAgentSettings, usePipelineOrchestratorRequestOccupancyLook, usePipelineOrchestratorResetNodePipelineDefaults, usePipelineOrchestratorResolvePipeline, usePipelineOrchestratorResumeForStorageMigration, usePipelineOrchestratorSetAgentCapabilities, usePipelineOrchestratorSetAgentDecodeLimits, usePipelineOrchestratorSetAgentInferenceDevices, usePipelineOrchestratorSetAgentMaxCameras, usePipelineOrchestratorSetAgentReachableHost, usePipelineOrchestratorSetCameraDetectionSource, usePipelineOrchestratorSetCameraSensors, usePipelineOrchestratorSetCameraStepSettings, usePipelineOrchestratorSetCameraStepToggle, usePipelineOrchestratorSetCameraSwitch, usePipelineOrchestratorSetCapabilityBinding, usePipelineOrchestratorSetLoadBalancingShares, usePipelineOrchestratorSetNodeStepSettings, usePipelineOrchestratorSetPipelineDevicePin, usePipelineOrchestratorSetShareSource, usePipelineOrchestratorStartNodeBenchmark, usePipelineOrchestratorSuggestShares, usePipelineOrchestratorUnassignAudio, usePipelineOrchestratorUnassignPipeline, usePipelineRunnerAbortNodeBench, usePipelineRunnerAttachCamera, usePipelineRunnerDetachCamera, usePipelineRunnerGetAllCameraMetrics, usePipelineRunnerGetCameraMetrics, usePipelineRunnerGetLocalCameras, usePipelineRunnerGetLocalLoad, usePipelineRunnerGetLocalMetrics, usePipelineRunnerGetNativeCrop, usePipelineRunnerGetNodeBenchStatus, usePipelineRunnerGetParkedTrackFrame, usePipelineRunnerParkTrackFrame, usePipelineRunnerReleaseParkedTrackFrames, usePipelineRunnerReportMotion, usePipelineRunnerRequestOccupancyBurst, usePipelineRunnerRunDetailSubtree, usePipelineRunnerRunStatelessStep, usePipelineRunnerStartNodeBench, usePlateGalleryAssignPlate, usePlateGalleryAssignPlates, usePlateGalleryCorrectPlateText, usePlateGalleryCreateVehicle, usePlateGalleryDeletePlate, usePlateGalleryDeleteVehicle, usePlateGalleryGetPlateByTrack, usePlateGalleryGetPlateMedia, usePlateGalleryListPlates, usePlateGalleryListVehicleSamples, usePlateGalleryListVehicles, usePlateGalleryRemoveVehicleSample, usePlateGalleryRenameVehicle, usePlateGallerySearchPlates, usePlateGallerySuggestPlateClusters, usePlateGalleryUnassignPlate, usePlateGalleryUnassignPlates, usePlatformProbeGetCapabilities, usePlatformProbeGetHardware, usePlatformProbeRescanAccelerators, usePlatformProbeResolveHwAccel, usePlatformProbeResolveInferenceConfig, usePlayerOverlayLayer, usePlayerOverlayLayers, usePlayerToolbarButton, usePlayerToolbarButtons, usePowerMeterGetStatus, usePowerSourceForceRestart, usePowerSourceGetStatus, usePowerSourcePowerOff, usePowerSourcePowerOn, usePresenceGetStatus, usePressureSensorGetStatus, usePrivacyMaskGetOptions, usePrivacyMaskGetStatus, usePrivacyMaskSetAudioEnabled, usePrivacyMaskSetMask, usePrompt, usePtzAutotrackGetSettings, usePtzAutotrackGetStatus, usePtzAutotrackSetEnabled, usePtzAutotrackSetSettings, usePtzCaptureHomeHere, usePtzContinuousMove, usePtzDeletePreset, usePtzGetHomePreset, usePtzGetHomeReturn, usePtzGetOptions, usePtzGetPosition, usePtzGetPresets, usePtzGetStatus, usePtzGoHome, usePtzGoToPreset, usePtzMove, usePtzSavePreset, usePtzSetAutofocus, usePtzSetHomePreset, usePtzSetHomeReturn, usePtzStop, useRebootReboot, useRecordEntriesDeleteEntry, useRecordEntriesListEntries, useRecordEntriesListEntryKinds, useRecordEntriesPutEntry, useRecordedPlayback, useRecordingArchiveApplyDeviceSettingsPatch, useRecordingArchiveCancelRelocateJob, useRecordingArchiveCancelStorageMigrationMove, useRecordingArchiveDeleteFootprint, useRecordingArchiveGetAvailabilityBatch, useRecordingArchiveGetDaysWithRecordingsBatch, useRecordingArchiveGetDeviceConfig, useRecordingArchiveGetDeviceLiveContribution, useRecordingArchiveGetDeviceSettingsContribution, useRecordingArchiveGetPlacement, useRecordingArchiveGetRelocateResidue, useRecordingArchiveGetStatus, useRecordingArchiveGetStorageMigrationMoveStatus, useRecordingArchiveGetStorageUsage, useRecordingArchiveListOpsLog, useRecordingArchiveListRelocateJobs, useRecordingArchiveLocateSegment, useRecordingArchivePauseForStorageMigration, useRecordingArchivePlanStorageRebalance, useRecordingArchivePruneFootage, useRecordingArchiveReadGopBytes, useRecordingArchiveReadSegmentBytes, useRecordingArchiveReadWindowBytes, useRecordingArchiveReconcileLedgerAgainstDisk, useRecordingArchiveRefreshStorageLocationsForMigration, useRecordingArchiveRelocateFootage, useRecordingArchiveRenderClip, useRecordingArchiveRenderGif, useRecordingArchiveRescanStorage, useRecordingArchiveResumeForStorageMigration, useRecordingArchiveSetDeviceConfig, useRecordingArchiveSetDevicePlacement, useRecordingArchiveStartStorageMigrationMove, useRecordingArchiveStartStorageRebalance, useRecordingExportCancelExport, useRecordingExportCreateExport, useRecordingExportDeleteExport, useRecordingExportGetDownloadUrl, useRecordingExportGetExport, useRecordingExportListExports, useRecordingExportReadExportBytes, useRecordingGetAvailability, useRecordingGetDaysWithRecordings, useRecordingGetPlayback, useRecordingGetPlaybackOptions, useRecordingListSources, useRecordingOnboardGetOptions, useRecordingOnboardGetStatus, useRecordingOnboardSetSettings, useRecordingSignalGetStatus, useRegisteredHotkeys, useRemoteComponent, useRemoteGetConfig, useRemoteLayoutComponentsListComponents, useRemoteListCommands, useRemoteSendCommand, useRemoteSendMediaCommand, useRemoteSetConfig, useRoleDisplayDefaults, useRunningStateGetStatus, useSceneMonitorCaptureReference, useSceneMonitorCreateScene, useSceneMonitorDeleteReference, useSceneMonitorDeleteScene, useSceneMonitorGetStatus, useSceneMonitorListScenes, useSceneMonitorListScenesBatch, useSceneMonitorRecheckNow, useSceneMonitorResetScene, useSceneMonitorUpdateScene, useSchedulersConflicts, useSchedulersCreate, useSchedulersDelete, useSchedulersGet, useSchedulersGetStatus, useSchedulersGetTraces, useSchedulersList, useSchedulersPreview, useSchedulersSetEnabled, useSchedulersUpdate, useScriptRunnerGetStatus, useScriptRunnerRun, useScriptRunnerStop, useScrubController, useSearchFieldHotkey, useServerManagementApplyServerUpdate, useServerManagementCheckServerUpdate, useServerManagementGetLaunchOverrides, useServerManagementGetServerPackageStatus, useServerManagementInstallDesktopUpdate, useServerManagementRestartServer, useServerManagementRollbackServerUpdate, useServerManagementSetLaunchOverrides, useSettingsStoreAggregate, useSettingsStoreCount, useSettingsStoreDeclareCollection, useSettingsStoreDelete, useSettingsStoreDeleteWhere, useSettingsStoreGet, useSettingsStoreHistogram, useSettingsStoreInsert, useSettingsStoreInsertMany, useSettingsStoreIsEmpty, useSettingsStoreQuery, useSettingsStoreSet, useSettingsStoreTransact, useSettingsStoreUpdate, useSettingsStoreUpdateWhere, useSettingsStoreUpsert, useSettingsStoreUpsertMany, useSmokeGetStatus, useSnapshotApplyDeviceSettingsPatch, useSnapshotGetDebugState, useSnapshotGetDeviceLiveContribution, useSnapshotGetDeviceSettingsContribution, useSnapshotGetSnapshot, useSnapshotGetSnapshotLinks, useSnapshotGetSnapshotOverview, useSnapshotGetStatus, useSnapshotInvalidateCache, useStationaryOverlay, useStorageAbortUpload, useStorageBeginDownload, useStorageBeginUpload, useStorageDelete, useStorageDeleteLocation, useStorageEndDownload, useStorageExists, useStorageFinalizeUpload, useStorageGetAvailableSpace, useStorageList, useStorageListDrainProgress, useStorageListLocationDeclarations, useStorageListLocations, useStorageListProviders, useStorageMigrationCancel, useStorageMigrationCleanupCancel, useStorageMigrationCleanupStart, useStorageMigrationCleanupStatus, useStorageMigrationDrain, useStorageMigrationHistory, useStorageMigrationMoverClearance, useStorageMigrationMovers, useStorageMigrationPlan, useStorageMigrationResidue, useStorageMigrationStart, useStorageMigrationStatus, useStorageRead, useStorageReadChunk, useStorageResolve, useStorageTestConfig, useStorageTestLocation, useStorageUpsertLocation, useStorageWrite, useStorageWriteChunk, useStoredGroupBy, useStreamBrokerAcquireEgressTranscode, useStreamBrokerApplyDeviceSettingsPatch, useStreamBrokerAssignProfile, useStreamBrokerFetchEventMedia, useStreamBrokerForgetDeviceHardware, useStreamBrokerGetAllRtspEntries, useStreamBrokerGetBrokerStats, useStreamBrokerGetDeviceAudioMute, useStreamBrokerGetDeviceLiveContribution, useStreamBrokerGetDeviceSettingsContribution, useStreamBrokerGetLiveViewerCounts, useStreamBrokerGetPreBufferInfo, useStreamBrokerGetRtspEntry, useStreamBrokerGetRtspPort, useStreamBrokerGetStreamUrl, useStreamBrokerGetStreamWithCodec, useStreamBrokerIsRtspEnabled, useStreamBrokerKillClient, useStreamBrokerListAllCameraStreams, useStreamBrokerListAllProfileSlots, useStreamBrokerListClients, useStreamBrokerProbeStream, useStreamBrokerProduceEventMedia, useStreamBrokerPublishCameraStream, useStreamBrokerPullAudioChunks, useStreamBrokerRegenerateRtspToken, useStreamBrokerReleaseEgressTranscode, useStreamBrokerReleaseStreamWithCodec, useStreamBrokerRenderPreBufferClip, useStreamBrokerReportStreamSignal, useStreamBrokerRestartProfile, useStreamBrokerRetractCameraStream, useStreamBrokerSetDeviceAudioMute, useStreamBrokerSetPreBufferDuration, useStreamBrokerSetRtspEnabled, useStreamBrokerSubscribeAudioChunks, useStreamBrokerUnassignProfile, useStreamBrokerUnsubscribeAudioChunks, useStreamCatalogGetCatalog, useStreamParamsGetConfigSchema, useStreamParamsGetOptions, useStreamParamsGetStatus, useStreamParamsSetProfile, useStreamSignalsListSignals, useSwitchGetStatus, useSwitchSetState, useSystem, useSystemDetectSiteLocation, useSystemFeatureFlags, useSystemForceRetentionCleanup, useSystemGetFailureContributions, useSystemGetLoadContributions, useSystemGetLoggingSettings, useSystemGetRequestCensus, useSystemGetRetentionConfig, useSystemGetSiteLocation, useSystemHealth, useSystemInfo, useSystemMutation, useSystemNetworkAddresses, useSystemQuery, useSystemSetLoggingSettings, useSystemSetRetentionConfig, useSystemSetSiteLocation, useTamperGetStatus, useTemperatureSensorGetStatus, useTemplateCreate, useTemplateDelete, useTemplateGet, useTemplateList, useTemplateUpdate, useTerminalSessionAdoptLegacyMonitor, useTerminalSessionClose, useTerminalSessionCreateInstance, useTerminalSessionDeleteInstance, useTerminalSessionListInstances, useTerminalSessionListLegacyCameras, useTerminalSessionListProfiles, useTerminalSessionListSessions, useTerminalSessionOpenSession, useTerminalSessionPullOutput, useTerminalSessionResize, useTerminalSessionSetInstanceEnabled, useTerminalSessionUpdateInstance, useTerminalSessionWriteInput, useThemeMode, useTimedRunCancel, useTimedRunGetStatus, useTimedRunRunFor, useToastOnToast, useTrainingCanaryResult, useTrainingCancelJob, useTrainingDiscardResult, useTrainingGetJob, useTrainingGetJobResult, useTrainingListBaseModels, useTrainingListCanaryTargets, useTrainingListJobs, useTrainingPlanJob, useTrainingRegisterResult, useTrainingRollbackCanary, useTrainingStartJob, useTrainingStartJobBatch, useTurnProviderGetTurnServers, useUiText, useUnitPreferences, useUpdateGetStatus, useUpdateInstallUpdate, useUrlQueryParam, useUserManagementConfirmTotp, useUserManagementCreateUser, useUserManagementDeleteUser, useUserManagementDisableTotp, useUserManagementFindUserByExternalIdentity, useUserManagementGetAdminBootstrapStatus, useUserManagementGetTotpStatus, useUserManagementListExternalIdentities, useUserManagementListOauthSessions, useUserManagementListUsers, useUserManagementMigrateRawSecrets, useUserManagementOauthExchangeCode, useUserManagementOauthIssueCode, useUserManagementOauthRefresh, useUserManagementOauthVerifyAccessToken, useUserManagementResetPassword, useUserManagementRevokeOauthSession, useUserManagementSetUserScopes, useUserManagementSetupTotp, useUserManagementUnlinkExternalIdentity, useUserManagementUpdateUser, useUserManagementValidateCredentials, useUserManagementVerifyTotp, useVacuumControlGetStatus, useVacuumControlLocate, useVacuumControlPause, useVacuumControlReturnToBase, useVacuumControlSetFanSpeed, useVacuumControlStart, useVacuumControlStop, useValveClose, useValveGetStatus, useValveOpen, useValveSetPosition, useValveStop, useVibrationGetStatus, useVideoclipsDialClipStream, useVideoclipsGetClipPlayback, useVideoclipsGetPlaybackOptions, useVideoclipsListClips, useVideoclipsListSources, useVideoclipsOfferClipBytes, useVideoclipsReadClipBytes, useVodPlayback, useWaterHeaterGetStatus, useWaterHeaterSetAway, useWaterHeaterSetOperationMode, useWaterHeaterSetTargetTemp, useWeatherGetStatus, useWebrtcSessionAddIceCandidate, useWebrtcSessionApplyDownlinkProbe, useWebrtcSessionCloseSession, useWebrtcSessionCreateSession, useWebrtcSessionGetIceCandidates, useWebrtcSessionGetSessionDebug, useWebrtcSessionGetSessionState, useWebrtcSessionHandleAnswer, useWebrtcSessionHandleOffer, useWebrtcSessionHasAdaptiveBitrate, useWebrtcSessionListStreams, useWidget, useWidgetMetadata, useWidgetRegistry, useZoneAnalyticsGetCameraHistory, useZoneAnalyticsGetCurrentSnapshot, useZoneAnalyticsGetCurrentSnapshotBatch, useZoneAnalyticsGetUnzonedHistory, useZoneAnalyticsGetZoneHistory, useZoneEditing, useZoneRulesListRules, useZoneRulesSetRules, useZonesAddZone, useZonesListZones, useZonesRemoveZone, useZonesUpdateZone, Save as ut, UtensilsCrossed as v, vacuumStateMeta, validateScopes, valveStateMeta, variantLabel, Hash as vn, ChevronLeft as vr, RadioTower as vt, Undo2 as w, waterHeaterPhase, waterHeaterTint, weatherConditionMeta, weatherTint, withHiddenChart, withPanel, withResolvedParentDetail, withUseRootModel, withoutModelScopedFields, withoutPanel, GraduationCap as wn, Car as wr, writeStoredGroupBy, Plug as wt, UserCheck as x, Hammer as xn, ChartLine as xr, Puzzle as xt, Users as y, HardDrive as yn, ChevronDown as yr, Radar as yt, Tag as z, EllipsisVertical as zn, BatteryMedium as zr, MoveVertical as zt };