@camstack/addon-provider-enpal 0.1.18 → 0.1.19
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/CHANGELOG.md +7 -0
- package/dist/addon.js +580 -396
- package/dist/addon.mjs +580 -396
- package/package.json +2 -2
package/dist/addon.mjs
CHANGED
|
@@ -6056,7 +6056,7 @@ var ZodIssueCode = {
|
|
|
6056
6056
|
var ZodFirstPartyTypeKind;
|
|
6057
6057
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6058
6058
|
//#endregion
|
|
6059
|
-
//#region ../types/dist/sleep-
|
|
6059
|
+
//#region ../types/dist/sleep-DyIxjZZt.mjs
|
|
6060
6060
|
/**
|
|
6061
6061
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6062
6062
|
* window to float samples (D455).
|
|
@@ -15261,6 +15261,32 @@ var CAP_VOCABULARY_BY_NAME = {
|
|
|
15261
15261
|
...SYSTEM_CAP_VOCABULARY
|
|
15262
15262
|
};
|
|
15263
15263
|
/**
|
|
15264
|
+
* Vocabulary actions by id (D983). An action step names a vocabulary action
|
|
15265
|
+
* (`cover.open`), never a raw cap method; this is the one lookup that turns the
|
|
15266
|
+
* id into its cap, method and effect — and a persisted legacy `cap` + `method`
|
|
15267
|
+
* pair back into the action id when exactly one action matches.
|
|
15268
|
+
*/
|
|
15269
|
+
function buildIndex() {
|
|
15270
|
+
const byId = /* @__PURE__ */ new Map();
|
|
15271
|
+
for (const [cap, entry] of Object.entries(CAP_VOCABULARY_BY_NAME)) {
|
|
15272
|
+
if (entry.scope !== "device") continue;
|
|
15273
|
+
for (const action of entry.actions ?? []) byId.set(action.id, {
|
|
15274
|
+
cap,
|
|
15275
|
+
action
|
|
15276
|
+
});
|
|
15277
|
+
}
|
|
15278
|
+
return byId;
|
|
15279
|
+
}
|
|
15280
|
+
var index;
|
|
15281
|
+
function actionIndex() {
|
|
15282
|
+
index ??= buildIndex();
|
|
15283
|
+
return index;
|
|
15284
|
+
}
|
|
15285
|
+
/** The vocabulary action with this id, or `undefined`. */
|
|
15286
|
+
function findVocabAction(actionId) {
|
|
15287
|
+
return actionIndex().get(actionId);
|
|
15288
|
+
}
|
|
15289
|
+
/**
|
|
15264
15290
|
* `addon-pages-source` — collection cap exposing per-provider raw page
|
|
15265
15291
|
* declarations. Every addon that contributes a UI page registers a
|
|
15266
15292
|
* provider here. The hub-side singleton aggregator (`addon-pages` cap,
|
|
@@ -44946,21 +44972,23 @@ function convertLegacyWhen(half) {
|
|
|
44946
44972
|
* (instants) and state leaves (durations). It replaces the flat trigger list
|
|
44947
44973
|
* plus the separate condition tree; the firing rule is in that file and in
|
|
44948
44974
|
* ADR "one tree".
|
|
44949
|
-
* - **Actions** — the `wait` and `
|
|
44975
|
+
* - **Actions** — the `wait` and device `command` steps, plus the `{kind:'code'}`
|
|
44950
44976
|
* fragment of §3.2.2. See {@link AutomationActionSchema}.
|
|
44951
44977
|
*
|
|
44952
44978
|
* A recipe stored in the old shape (`triggers` + `conditions`) still LOADS:
|
|
44953
44979
|
* {@link AutomationRecipeSchema} (the parse-anywhere schema) converts it on parse. Nothing writes it.
|
|
44954
44980
|
*/
|
|
44955
44981
|
/**
|
|
44956
|
-
* One action step: `wait`, or a `
|
|
44982
|
+
* One action step: `wait`, or a device `command`.
|
|
44957
44983
|
*
|
|
44958
|
-
* A
|
|
44959
|
-
* `{ $var }` resolved from the run's
|
|
44960
|
-
*
|
|
44961
|
-
*
|
|
44962
|
-
*
|
|
44963
|
-
*
|
|
44984
|
+
* A command step names a VOCABULARY action (`cover.open`) and who it acts on
|
|
44985
|
+
* (D983: `devices`, a `domain`, or a `{ $var }` resolved from the run's
|
|
44986
|
+
* variables). It never names a cap method: the step runner turns the action
|
|
44987
|
+
* id into its cap + method through the vocabulary index when the step runs
|
|
44988
|
+
* (`vocabCall`), the one place that mapping happens. The step runner
|
|
44989
|
+
* (`runSteps`) owns the device-scope check, the stop-at-first-failure and the
|
|
44990
|
+
* variable substitution, once, for every caller — automations, Actions, and
|
|
44991
|
+
* the notification centre, which runs only Actions (planning#473).
|
|
44964
44992
|
*/
|
|
44965
44993
|
/** The longest one `wait` step lasts. It is cut by a restart of the run and does not survive a hub restart. */
|
|
44966
44994
|
var WAIT_MAX_SECONDS = 3600;
|
|
@@ -44969,39 +44997,22 @@ var AutomationWaitStepSchema = object({
|
|
|
44969
44997
|
kind: literal("wait"),
|
|
44970
44998
|
seconds: number$1().min(0).max(WAIT_MAX_SECONDS, WAIT_TOO_LONG)
|
|
44971
44999
|
});
|
|
44972
|
-
/** The legacy `deviceId` of a cap step: still READ, never written (D983). */
|
|
44973
|
-
var LegacyStepDeviceSchema = union([
|
|
44974
|
-
number$1().int(),
|
|
44975
|
-
array(number$1().int()).min(1),
|
|
44976
|
-
object({ $var: string().min(1) })
|
|
44977
|
-
]);
|
|
44978
45000
|
/**
|
|
44979
|
-
* The fields of a
|
|
44980
|
-
*
|
|
44981
|
-
* device); a step is {@link AutomationCapStepSchema}.
|
|
45001
|
+
* The fields of a command step, before the vocabulary check. A step is
|
|
45002
|
+
* {@link AutomationCommandStepSchema}.
|
|
44982
45003
|
*/
|
|
44983
|
-
var
|
|
44984
|
-
kind: literal("
|
|
44985
|
-
/**
|
|
44986
|
-
|
|
44987
|
-
|
|
44988
|
-
|
|
44989
|
-
* cap + method match exactly one vocabulary action.
|
|
44990
|
-
*/
|
|
44991
|
-
actionId: string().min(1).optional(),
|
|
44992
|
-
/** WHO the step acts on. The only shape that is written. */
|
|
44993
|
-
target: ActionTargetSchema.optional(),
|
|
45004
|
+
var AutomationCommandStepBaseSchema = object({
|
|
45005
|
+
kind: literal("command"),
|
|
45006
|
+
/** WHO the step acts on. */
|
|
45007
|
+
target: ActionTargetSchema,
|
|
45008
|
+
/** The vocabulary action this step performs (`cover.open`). */
|
|
45009
|
+
actionId: string().min(1),
|
|
44994
45010
|
/**
|
|
44995
|
-
*
|
|
44996
|
-
*
|
|
44997
|
-
*
|
|
45011
|
+
* The values of the action's OPEN args (`position`, `presetId`); the args
|
|
45012
|
+
* the vocabulary bakes into the action are added when the step runs. Values
|
|
45013
|
+
* may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
|
|
45014
|
+
* SUBSTITUTE and do not evaluate (§3.2.3).
|
|
44998
45015
|
*/
|
|
44999
|
-
deviceId: LegacyStepDeviceSchema.optional(),
|
|
45000
|
-
cap: string().min(1),
|
|
45001
|
-
method: string().min(1),
|
|
45002
|
-
/** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
|
|
45003
|
-
* SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
|
|
45004
|
-
* the expression leaf. */
|
|
45005
45016
|
args: record(string(), unknown()).optional(),
|
|
45006
45017
|
/**
|
|
45007
45018
|
* The unit the person picked per arg (display only). `args` always hold the
|
|
@@ -45010,18 +45021,20 @@ var AutomationCapStepBaseSchema = object({
|
|
|
45010
45021
|
*/
|
|
45011
45022
|
argUnits: record(string(), string().min(1)).optional()
|
|
45012
45023
|
});
|
|
45024
|
+
/** The vocabulary check every command step passes: the action exists. */
|
|
45025
|
+
function refineKnownAction(step, ctx) {
|
|
45026
|
+
if (findVocabAction(step.actionId) === void 0) ctx.addIssue({
|
|
45027
|
+
code: "custom",
|
|
45028
|
+
message: `"${step.actionId}" is not a vocabulary action id`,
|
|
45029
|
+
path: ["actionId"]
|
|
45030
|
+
});
|
|
45031
|
+
}
|
|
45013
45032
|
/**
|
|
45014
|
-
* The steps an internal Action may contain:
|
|
45033
|
+
* The steps an internal Action may contain: command and wait, and nothing that can
|
|
45015
45034
|
* call back into an Action — so an Action can never reach itself (no cycles).
|
|
45016
45035
|
* This is the LEAF shape: no condition of its own.
|
|
45017
45036
|
*/
|
|
45018
|
-
var LeafActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema,
|
|
45019
|
-
message: "a cap step needs a target",
|
|
45020
|
-
path: ["target"]
|
|
45021
|
-
}).refine((step) => step.target?.kind !== "domain" || step.actionId !== void 0, {
|
|
45022
|
-
message: "a domain target needs the vocabulary action it applies to (actionId)",
|
|
45023
|
-
path: ["actionId"]
|
|
45024
|
-
})]);
|
|
45037
|
+
var LeafActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCommandStepBaseSchema.superRefine(refineKnownAction)]);
|
|
45025
45038
|
/**
|
|
45026
45039
|
* The optional guard of a step (#472): `if` is the ONE `when` tree (D980), read
|
|
45027
45040
|
* on the state mirror when the step is reached; `else` runs when it is false.
|
|
@@ -45042,13 +45055,7 @@ var GuardedWaitStepSchema = AutomationWaitStepSchema.extend(stepGuardShape).refi
|
|
|
45042
45055
|
* same two step kinds an automation runs, minus a guard that reads the
|
|
45043
45056
|
* automation's trigger, which such a list does not have.
|
|
45044
45057
|
*/
|
|
45045
|
-
var ActionStepSchema = discriminatedUnion("kind", [GuardedWaitStepSchema,
|
|
45046
|
-
message: "a cap step needs a target",
|
|
45047
|
-
path: ["target"]
|
|
45048
|
-
}).refine((step) => step.target?.kind !== "domain" || step.actionId !== void 0, {
|
|
45049
|
-
message: "a domain target needs the vocabulary action it applies to (actionId)",
|
|
45050
|
-
path: ["actionId"]
|
|
45051
|
-
}).refine((step) => step.else === void 0 || step.if !== void 0, elseNeedsIf)]).superRefine((step, ctx) => {
|
|
45058
|
+
var ActionStepSchema = discriminatedUnion("kind", [GuardedWaitStepSchema, AutomationCommandStepBaseSchema.extend(stepGuardShape).superRefine(refineKnownAction).refine((step) => step.else === void 0 || step.if !== void 0, elseNeedsIf)]).superRefine((step, ctx) => {
|
|
45052
45059
|
if (step.if !== void 0 && hasTriggeredByLeaves(step.if)) ctx.addIssue({
|
|
45053
45060
|
code: "custom",
|
|
45054
45061
|
message: TRIGGERED_BY_NEEDS_AUTOMATION,
|
|
@@ -45063,17 +45070,11 @@ var ActionStepSchema = discriminatedUnion("kind", [GuardedWaitStepSchema, Automa
|
|
|
45063
45070
|
var continueOnErrorShape = {
|
|
45064
45071
|
/** A failure of this step is traced `failed-continued` and the next step runs. */
|
|
45065
45072
|
continueOnError: literal(true).optional() };
|
|
45066
|
-
/** An automation's
|
|
45067
|
-
var
|
|
45073
|
+
/** An automation's command step: the shared guarded command step, plus `continueOnError`. */
|
|
45074
|
+
var AutomationGuardedCommandStepSchema = AutomationCommandStepBaseSchema.extend({
|
|
45068
45075
|
...stepGuardShape,
|
|
45069
45076
|
...continueOnErrorShape
|
|
45070
|
-
}).refine((step) => step.
|
|
45071
|
-
message: "a cap step needs a target",
|
|
45072
|
-
path: ["target"]
|
|
45073
|
-
}).refine((step) => step.target?.kind !== "domain" || step.actionId !== void 0, {
|
|
45074
|
-
message: "a domain target needs the vocabulary action it applies to (actionId)",
|
|
45075
|
-
path: ["actionId"]
|
|
45076
|
-
}).refine((step) => step.else === void 0 || step.if !== void 0, elseNeedsIf);
|
|
45077
|
+
}).superRefine(refineKnownAction).refine((step) => step.else === void 0 || step.if !== void 0, elseNeedsIf);
|
|
45077
45078
|
/** End the run here, on purpose. `reason` may carry `{{vars.x}}` slots. */
|
|
45078
45079
|
var AutomationStopStepSchema = object({
|
|
45079
45080
|
kind: literal("stop"),
|
|
@@ -45153,13 +45154,7 @@ function nestTooDeep(issue) {
|
|
|
45153
45154
|
}
|
|
45154
45155
|
var plainStepSchemas = [
|
|
45155
45156
|
AutomationWaitStepSchema.strict(),
|
|
45156
|
-
|
|
45157
|
-
message: "a cap step needs a target",
|
|
45158
|
-
path: ["target"]
|
|
45159
|
-
}).refine((step) => step.target?.kind !== "domain" || step.actionId !== void 0, {
|
|
45160
|
-
message: "a domain target needs the vocabulary action it applies to (actionId)",
|
|
45161
|
-
path: ["actionId"]
|
|
45162
|
-
}),
|
|
45157
|
+
AutomationCommandStepBaseSchema.extend(continueOnErrorShape).strict().superRefine(refineKnownAction),
|
|
45163
45158
|
AutomationStopStepSchema.omit({ if: true }).strict(),
|
|
45164
45159
|
AutomationSetStepSchema.omit({ if: true }).strict(),
|
|
45165
45160
|
AutomationRunActionStepSchema.strict()
|
|
@@ -45170,7 +45165,7 @@ var plainStepSchemas = [
|
|
|
45170
45165
|
*/
|
|
45171
45166
|
var AutomationBranchStepSchema = discriminatedUnion("kind", plainStepSchemas, { error: nestTooDeep });
|
|
45172
45167
|
/** A step that can run beside others: it writes no variable and does not end the run. */
|
|
45173
|
-
var AutomationParallelMemberSchema = AutomationBranchStepSchema.refine((step) => step.kind === "
|
|
45168
|
+
var AutomationParallelMemberSchema = AutomationBranchStepSchema.refine((step) => step.kind === "command" || step.kind === "action" || step.kind === "wait", "a parallel holds device commands, actions and waits only: a set or a stop beside other steps has no order");
|
|
45174
45169
|
/**
|
|
45175
45170
|
* Several steps at once (#500): all are started together and all are awaited.
|
|
45176
45171
|
* A failure fails the run once the others finished, as in a sequence; a member
|
|
@@ -45250,7 +45245,7 @@ var AutomationBodyStepSchema = discriminatedUnion("kind", [
|
|
|
45250
45245
|
var AutomationRepeatStepSchema = repeatSchemaOf(AutomationBodyStepSchema);
|
|
45251
45246
|
var AutomationActionSchema = discriminatedUnion("kind", [
|
|
45252
45247
|
GuardedWaitStepSchema,
|
|
45253
|
-
|
|
45248
|
+
AutomationGuardedCommandStepSchema,
|
|
45254
45249
|
AutomationStopStepSchema,
|
|
45255
45250
|
AutomationSetStepSchema,
|
|
45256
45251
|
chooseSchemaOf(AutomationBodyStepSchema),
|
|
@@ -45321,110 +45316,6 @@ function convertLegacyRecipe(legacy) {
|
|
|
45321
45316
|
};
|
|
45322
45317
|
}
|
|
45323
45318
|
var AutomationRecipeSchema = union([CurrentAutomationRecipeSchema, LegacyAutomationRecipeSchema.transform(convertLegacyRecipe)]);
|
|
45324
|
-
var DETECTION_DESCRIPTIONS = {
|
|
45325
|
-
deviceId: "the camera that saw it",
|
|
45326
|
-
className: "what it saw",
|
|
45327
|
-
trackId: "the track",
|
|
45328
|
-
score: "how sure the detector was",
|
|
45329
|
-
label: "the label it matched (a name, a plate), empty when none"
|
|
45330
|
-
};
|
|
45331
|
-
var STATIONARY_DESCRIPTIONS = {
|
|
45332
|
-
deviceId: "the camera that saw it",
|
|
45333
|
-
className: "what it saw",
|
|
45334
|
-
zones: "the zones it is in",
|
|
45335
|
-
phase: "appeared or departed",
|
|
45336
|
-
entryId: "the stopped object"
|
|
45337
|
-
};
|
|
45338
|
-
var BECOMES_DESCRIPTIONS = {
|
|
45339
|
-
deviceId: "the device that changed",
|
|
45340
|
-
from: "the value before the change, empty when it is not known",
|
|
45341
|
-
to: "the value it changed to"
|
|
45342
|
-
};
|
|
45343
|
-
/**
|
|
45344
|
-
* A fire's payload is offered too, as `data.<path>` (`{{vars.data.channel}}`):
|
|
45345
|
-
* those names depend on the device, so they are not in this list.
|
|
45346
|
-
*/
|
|
45347
|
-
var FIRED_DESCRIPTIONS = {
|
|
45348
|
-
deviceId: "the device that fired",
|
|
45349
|
-
eventType: "the event, as the device names it",
|
|
45350
|
-
sourceId: "the part of the device that fired (a button), empty when it names none",
|
|
45351
|
-
eventKind: "the kind of press (press, long-press …), empty when the device declares none"
|
|
45352
|
-
};
|
|
45353
|
-
function describe$1(descriptions) {
|
|
45354
|
-
return Object.entries(descriptions).map(([name, description]) => ({
|
|
45355
|
-
name,
|
|
45356
|
-
description
|
|
45357
|
-
}));
|
|
45358
|
-
}
|
|
45359
|
-
describe$1(DETECTION_DESCRIPTIONS);
|
|
45360
|
-
describe$1(STATIONARY_DESCRIPTIONS);
|
|
45361
|
-
describe$1(FIRED_DESCRIPTIONS).map((v) => v.name === "deviceId" ? {
|
|
45362
|
-
...v,
|
|
45363
|
-
hintKey: "firedDeviceId"
|
|
45364
|
-
} : v);
|
|
45365
|
-
describe$1(BECOMES_DESCRIPTIONS).map((v) => v.name === "deviceId" ? {
|
|
45366
|
-
...v,
|
|
45367
|
-
hintKey: "becomesDeviceId"
|
|
45368
|
-
} : v);
|
|
45369
|
-
new Set(Object.values(COCO_TO_MACRO.mapping));
|
|
45370
|
-
/**
|
|
45371
|
-
* Generic stateless event emitter. Installed on a `DeviceType.EventEmitter`
|
|
45372
|
-
* device. Carries the device's EXACT declared event vocabulary verbatim
|
|
45373
|
-
* (NO normalization). Two shapes:
|
|
45374
|
-
* - structured source (HA `event.*` entity) → `vocabulary` is the fixed
|
|
45375
|
-
* declared set (e.g. press_short, press_long, …).
|
|
45376
|
-
* - generic/legacy source (HA bus events, e.g. zha_event) → `vocabulary`
|
|
45377
|
-
* is [] (open) and `lastEvent.data` carries the complex payload.
|
|
45378
|
-
* `vocabulary` (D1044) names each event for a person and types it for a
|
|
45379
|
-
* rule; `eventTypes` is its list of native tokens, kept for older readers.
|
|
45380
|
-
* A fire names the part of the device it came from in `sourceId` when the
|
|
45381
|
-
* vocabulary declares sources (a remote's buttons).
|
|
45382
|
-
* `seq` is monotonic so two identical events still produce distinct slice writes.
|
|
45383
|
-
*/
|
|
45384
|
-
var EventFireSchema = object({
|
|
45385
|
-
deviceId: number$1(),
|
|
45386
|
-
eventType: string(),
|
|
45387
|
-
sourceId: string().optional(),
|
|
45388
|
-
data: record(string(), unknown()).nullable(),
|
|
45389
|
-
timestamp: number$1().meta(readingMeta("none")),
|
|
45390
|
-
seq: number$1().meta(readingMeta("count"))
|
|
45391
|
-
});
|
|
45392
|
-
var EventEmitterStatusSchema = object({
|
|
45393
|
-
eventTypes: array(string()),
|
|
45394
|
-
/**
|
|
45395
|
-
* Required of a provider by the type. A status written before the field
|
|
45396
|
-
* existed still parses, as an empty vocabulary: read it through
|
|
45397
|
-
* `readEventVocabulary`, which then answers with the plain tokens.
|
|
45398
|
-
*/
|
|
45399
|
-
vocabulary: array(EventVocabularyEntrySchema).default([]),
|
|
45400
|
-
lastEvent: EventFireSchema.nullable(),
|
|
45401
|
-
eventCountSinceStart: number$1().meta(readingMeta("count"))
|
|
45402
|
-
});
|
|
45403
|
-
var eventEmitterCapability = {
|
|
45404
|
-
name: "event-emitter",
|
|
45405
|
-
scope: "device",
|
|
45406
|
-
deviceNative: true,
|
|
45407
|
-
mode: "singleton",
|
|
45408
|
-
deviceTypes: [DeviceType.EventEmitter],
|
|
45409
|
-
methods: {},
|
|
45410
|
-
events: { onEvent: { data: EventFireSchema } },
|
|
45411
|
-
status: {
|
|
45412
|
-
schema: EventEmitterStatusSchema,
|
|
45413
|
-
kind: "push"
|
|
45414
|
-
},
|
|
45415
|
-
runtimeState: EventEmitterStatusSchema,
|
|
45416
|
-
/**
|
|
45417
|
-
* Runtime-state durability: **session** — `eventCountSinceStart` names its own scope.
|
|
45418
|
-
*
|
|
45419
|
-
* See `RuntimeStateDurability`. Enforced by
|
|
45420
|
-
* `scripts/check-runtime-state-durability.ts`.
|
|
45421
|
-
*/
|
|
45422
|
-
durability: "session",
|
|
45423
|
-
/**
|
|
45424
|
-
* History (D850): none — `eventCountSinceStart` resets with the addon; events live in ledgers.
|
|
45425
|
-
*/
|
|
45426
|
-
history: "none"
|
|
45427
|
-
};
|
|
45428
45319
|
/**
|
|
45429
45320
|
* Schedulers (D983) — an entity that performs actions over the day.
|
|
45430
45321
|
*
|
|
@@ -45823,6 +45714,110 @@ var AutomationStateDocSchema = object({
|
|
|
45823
45714
|
lastRunStartedAt: number$1().nullable(),
|
|
45824
45715
|
traces: array(AutomationRunTraceSchema)
|
|
45825
45716
|
});
|
|
45717
|
+
var DETECTION_DESCRIPTIONS = {
|
|
45718
|
+
deviceId: "the camera that saw it",
|
|
45719
|
+
className: "what it saw",
|
|
45720
|
+
trackId: "the track",
|
|
45721
|
+
score: "how sure the detector was",
|
|
45722
|
+
label: "the label it matched (a name, a plate), empty when none"
|
|
45723
|
+
};
|
|
45724
|
+
var STATIONARY_DESCRIPTIONS = {
|
|
45725
|
+
deviceId: "the camera that saw it",
|
|
45726
|
+
className: "what it saw",
|
|
45727
|
+
zones: "the zones it is in",
|
|
45728
|
+
phase: "appeared or departed",
|
|
45729
|
+
entryId: "the stopped object"
|
|
45730
|
+
};
|
|
45731
|
+
var BECOMES_DESCRIPTIONS = {
|
|
45732
|
+
deviceId: "the device that changed",
|
|
45733
|
+
from: "the value before the change, empty when it is not known",
|
|
45734
|
+
to: "the value it changed to"
|
|
45735
|
+
};
|
|
45736
|
+
/**
|
|
45737
|
+
* A fire's payload is offered too, as `data.<path>` (`{{vars.data.channel}}`):
|
|
45738
|
+
* those names depend on the device, so they are not in this list.
|
|
45739
|
+
*/
|
|
45740
|
+
var FIRED_DESCRIPTIONS = {
|
|
45741
|
+
deviceId: "the device that fired",
|
|
45742
|
+
eventType: "the event, as the device names it",
|
|
45743
|
+
sourceId: "the part of the device that fired (a button), empty when it names none",
|
|
45744
|
+
eventKind: "the kind of press (press, long-press …), empty when the device declares none"
|
|
45745
|
+
};
|
|
45746
|
+
function describe$1(descriptions) {
|
|
45747
|
+
return Object.entries(descriptions).map(([name, description]) => ({
|
|
45748
|
+
name,
|
|
45749
|
+
description
|
|
45750
|
+
}));
|
|
45751
|
+
}
|
|
45752
|
+
describe$1(DETECTION_DESCRIPTIONS);
|
|
45753
|
+
describe$1(STATIONARY_DESCRIPTIONS);
|
|
45754
|
+
describe$1(FIRED_DESCRIPTIONS).map((v) => v.name === "deviceId" ? {
|
|
45755
|
+
...v,
|
|
45756
|
+
hintKey: "firedDeviceId"
|
|
45757
|
+
} : v);
|
|
45758
|
+
describe$1(BECOMES_DESCRIPTIONS).map((v) => v.name === "deviceId" ? {
|
|
45759
|
+
...v,
|
|
45760
|
+
hintKey: "becomesDeviceId"
|
|
45761
|
+
} : v);
|
|
45762
|
+
new Set(Object.values(COCO_TO_MACRO.mapping));
|
|
45763
|
+
/**
|
|
45764
|
+
* Generic stateless event emitter. Installed on a `DeviceType.EventEmitter`
|
|
45765
|
+
* device. Carries the device's EXACT declared event vocabulary verbatim
|
|
45766
|
+
* (NO normalization). Two shapes:
|
|
45767
|
+
* - structured source (HA `event.*` entity) → `vocabulary` is the fixed
|
|
45768
|
+
* declared set (e.g. press_short, press_long, …).
|
|
45769
|
+
* - generic/legacy source (HA bus events, e.g. zha_event) → `vocabulary`
|
|
45770
|
+
* is [] (open) and `lastEvent.data` carries the complex payload.
|
|
45771
|
+
* `vocabulary` (D1044) names each event for a person and types it for a
|
|
45772
|
+
* rule; `eventTypes` is its list of native tokens, kept for older readers.
|
|
45773
|
+
* A fire names the part of the device it came from in `sourceId` when the
|
|
45774
|
+
* vocabulary declares sources (a remote's buttons).
|
|
45775
|
+
* `seq` is monotonic so two identical events still produce distinct slice writes.
|
|
45776
|
+
*/
|
|
45777
|
+
var EventFireSchema = object({
|
|
45778
|
+
deviceId: number$1(),
|
|
45779
|
+
eventType: string(),
|
|
45780
|
+
sourceId: string().optional(),
|
|
45781
|
+
data: record(string(), unknown()).nullable(),
|
|
45782
|
+
timestamp: number$1().meta(readingMeta("none")),
|
|
45783
|
+
seq: number$1().meta(readingMeta("count"))
|
|
45784
|
+
});
|
|
45785
|
+
var EventEmitterStatusSchema = object({
|
|
45786
|
+
eventTypes: array(string()),
|
|
45787
|
+
/**
|
|
45788
|
+
* Required of a provider by the type. A status written before the field
|
|
45789
|
+
* existed still parses, as an empty vocabulary: read it through
|
|
45790
|
+
* `readEventVocabulary`, which then answers with the plain tokens.
|
|
45791
|
+
*/
|
|
45792
|
+
vocabulary: array(EventVocabularyEntrySchema).default([]),
|
|
45793
|
+
lastEvent: EventFireSchema.nullable(),
|
|
45794
|
+
eventCountSinceStart: number$1().meta(readingMeta("count"))
|
|
45795
|
+
});
|
|
45796
|
+
var eventEmitterCapability = {
|
|
45797
|
+
name: "event-emitter",
|
|
45798
|
+
scope: "device",
|
|
45799
|
+
deviceNative: true,
|
|
45800
|
+
mode: "singleton",
|
|
45801
|
+
deviceTypes: [DeviceType.EventEmitter],
|
|
45802
|
+
methods: {},
|
|
45803
|
+
events: { onEvent: { data: EventFireSchema } },
|
|
45804
|
+
status: {
|
|
45805
|
+
schema: EventEmitterStatusSchema,
|
|
45806
|
+
kind: "push"
|
|
45807
|
+
},
|
|
45808
|
+
runtimeState: EventEmitterStatusSchema,
|
|
45809
|
+
/**
|
|
45810
|
+
* Runtime-state durability: **session** — `eventCountSinceStart` names its own scope.
|
|
45811
|
+
*
|
|
45812
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
45813
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
45814
|
+
*/
|
|
45815
|
+
durability: "session",
|
|
45816
|
+
/**
|
|
45817
|
+
* History (D850): none — `eventCountSinceStart` resets with the addon; events live in ledgers.
|
|
45818
|
+
*/
|
|
45819
|
+
history: "none"
|
|
45820
|
+
};
|
|
45826
45821
|
/**
|
|
45827
45822
|
* Actions — named, runnable things an operator (or an automation) can start,
|
|
45828
45823
|
* declared as LIST ENTRIES, never as devices.
|
|
@@ -46002,6 +45997,177 @@ var UnitWarningSchema = object({
|
|
|
46002
45997
|
assumedUnit: string(),
|
|
46003
45998
|
message: string()
|
|
46004
45999
|
});
|
|
46000
|
+
/**
|
|
46001
|
+
* `device-export` — collection cap for addons that export camstack
|
|
46002
|
+
* devices to external ecosystems (HomeAssistant via MQTT discovery,
|
|
46003
|
+
* HomeKit/HAP, Alexa Smart Home, …).
|
|
46004
|
+
*
|
|
46005
|
+
* No `ecosystem` enum — the addon id identifies the export target.
|
|
46006
|
+
* Each addon owns its mapping logic in its own settings UI. The cap
|
|
46007
|
+
* exposes only the COMMON surface: link state, supported device
|
|
46008
|
+
* kinds (so the UI can filter the device picker), and per-device
|
|
46009
|
+
* expose/unexpose.
|
|
46010
|
+
*
|
|
46011
|
+
* INSTANCES. One export addon can serve several independent targets (a
|
|
46012
|
+
* HomeKit bridge, a Home Assistant broker). `listInstances` names them.
|
|
46013
|
+
* `instanceId` on a READ is optional: absent = the whole addon (linked if any
|
|
46014
|
+
* enabled instance is, `exposedDeviceCount` = distinct devices, `setup` = the
|
|
46015
|
+
* default instance's); present = that instance; an id the provider does not
|
|
46016
|
+
* serve is refused with `ExportInstanceUnknownError` (`export-instance-unknown`),
|
|
46017
|
+
* never answered empty. `instanceId` on a WRITE is REQUIRED: a membership
|
|
46018
|
+
* change always names the target it changes. A single-instance provider
|
|
46019
|
+
* accepts an absent id on a read or its own id, and refuses any other.
|
|
46020
|
+
*/
|
|
46021
|
+
/** Which instance of an export addon a call addresses. Absent on a read = the whole addon. */
|
|
46022
|
+
var InstanceIdSchema$1 = string().min(1);
|
|
46023
|
+
var InstancePinSchema = object({ instanceId: InstanceIdSchema$1.optional() });
|
|
46024
|
+
/** One independent export target of an addon. */
|
|
46025
|
+
var ExportInstanceSchema = object({
|
|
46026
|
+
instanceId: InstanceIdSchema$1,
|
|
46027
|
+
name: string(),
|
|
46028
|
+
enabled: boolean(),
|
|
46029
|
+
kind: string().optional(),
|
|
46030
|
+
/**
|
|
46031
|
+
* What this instance's platform accepts as a device name, in one operator-facing sentence
|
|
46032
|
+
* (D1049). The derived "Name on <instance>" field shows it; absent = the field says nothing
|
|
46033
|
+
* about the rule.
|
|
46034
|
+
*/
|
|
46035
|
+
nameRule: string().optional()
|
|
46036
|
+
});
|
|
46037
|
+
var LinkStateSchema = _enum([
|
|
46038
|
+
"unlinked",
|
|
46039
|
+
"linked",
|
|
46040
|
+
"error"
|
|
46041
|
+
]);
|
|
46042
|
+
/**
|
|
46043
|
+
* A single label/value row surfaced in the export panel's "Setup"
|
|
46044
|
+
* section. Rendered with a copy-to-clipboard button. `secret: true`
|
|
46045
|
+
* rows are masked by default with a reveal toggle (client ids,
|
|
46046
|
+
* secrets, …).
|
|
46047
|
+
*/
|
|
46048
|
+
var ExportSetupFieldSchema = object({
|
|
46049
|
+
label: string(),
|
|
46050
|
+
value: string(),
|
|
46051
|
+
/** Mask the value by default + render a reveal toggle (client id, secrets). */
|
|
46052
|
+
secret: boolean().optional()
|
|
46053
|
+
});
|
|
46054
|
+
/**
|
|
46055
|
+
* Generic, addon-agnostic pairing/account block. Any export addon can
|
|
46056
|
+
* surface a scannable QR, a set of copyable label/value rows, and a
|
|
46057
|
+
* free-form operator note — the `DeviceExportPanel` renders whatever
|
|
46058
|
+
* the provider supplies and skips the section entirely when `setup`
|
|
46059
|
+
* is unset.
|
|
46060
|
+
*/
|
|
46061
|
+
var ExportSetupSchema = object({
|
|
46062
|
+
/** A string to render as a scannable QR — HAP `X-HM://…` URI, a pairing URL, etc. Omitted when there's nothing to scan. */
|
|
46063
|
+
qr: string().optional(),
|
|
46064
|
+
/** Label/value rows shown with a copy button (HAP setup code, OAuth URLs, client id, linked-account count, …). */
|
|
46065
|
+
fields: array(ExportSetupFieldSchema).readonly().optional(),
|
|
46066
|
+
/** Free-form operator instructions rendered above the fields. */
|
|
46067
|
+
note: string().optional()
|
|
46068
|
+
});
|
|
46069
|
+
var DeviceExportStatusSchema = object({
|
|
46070
|
+
linkState: LinkStateSchema,
|
|
46071
|
+
exposedDeviceCount: number$1(),
|
|
46072
|
+
error: string().optional(),
|
|
46073
|
+
/**
|
|
46074
|
+
* Optional pairing/account info the panel renders in a generic
|
|
46075
|
+
* "Setup" section. Addon-agnostic — the addon id identifies the
|
|
46076
|
+
* export target, never an `ecosystem` key here.
|
|
46077
|
+
*/
|
|
46078
|
+
setup: ExportSetupSchema.optional()
|
|
46079
|
+
});
|
|
46080
|
+
var DeviceKindSchema = string();
|
|
46081
|
+
/**
|
|
46082
|
+
* EXPOSED NAME. What one instance calls a device on its platform, when it should not be the
|
|
46083
|
+
* device's own name. The exporter owns it: it is stored per instance in the exporter's per-device
|
|
46084
|
+
* store (D865), validated by the exporter against its platform's naming rules, and never reaches
|
|
46085
|
+
* the exported id — a rename updates the SAME device on the platform, never a second one.
|
|
46086
|
+
* Blank or `null` = the device's own name. A name the platform would refuse is refused with
|
|
46087
|
+
* `ExportNameRefusedError` (`export-name-refused`), whose message says why.
|
|
46088
|
+
*/
|
|
46089
|
+
var ExposedDeviceSchema = object({
|
|
46090
|
+
deviceId: string(),
|
|
46091
|
+
exposedAs: string().optional(),
|
|
46092
|
+
/** The operator's name for this device on this instance; absent = the device's own name. */
|
|
46093
|
+
exposedName: string().optional(),
|
|
46094
|
+
capabilities: array(string()).optional()
|
|
46095
|
+
});
|
|
46096
|
+
var ExposeInputSchema = object({
|
|
46097
|
+
instanceId: InstanceIdSchema$1,
|
|
46098
|
+
deviceId: string(),
|
|
46099
|
+
capabilities: array(string()).optional(),
|
|
46100
|
+
/** Set the exposed name in the same call; absent = leave it as it is, blank/null = clear it. */
|
|
46101
|
+
exposedName: string().nullable().optional()
|
|
46102
|
+
});
|
|
46103
|
+
var SetExposedNameInputSchema = object({
|
|
46104
|
+
instanceId: InstanceIdSchema$1,
|
|
46105
|
+
deviceId: string(),
|
|
46106
|
+
/** Blank or null = the device's own name. */
|
|
46107
|
+
name: string().nullable(),
|
|
46108
|
+
/**
|
|
46109
|
+
* Validate only: refuse exactly as a real call would, write nothing. A caller saving several
|
|
46110
|
+
* names at once checks every one first, so one refusal writes none (D1049).
|
|
46111
|
+
*/
|
|
46112
|
+
dryRun: boolean().optional()
|
|
46113
|
+
});
|
|
46114
|
+
var UnexposeInputSchema = object({
|
|
46115
|
+
instanceId: InstanceIdSchema$1,
|
|
46116
|
+
deviceId: string()
|
|
46117
|
+
});
|
|
46118
|
+
/**
|
|
46119
|
+
* What an exporter may expose besides devices (D968). An action and a
|
|
46120
|
+
* notification target are LIST ENTRIES, never devices (D954): they enter an
|
|
46121
|
+
* exporter's own selection, not the device registry.
|
|
46122
|
+
*/
|
|
46123
|
+
var ExportEntityKindSchema = _enum([
|
|
46124
|
+
"device",
|
|
46125
|
+
"action",
|
|
46126
|
+
"notifier"
|
|
46127
|
+
]);
|
|
46128
|
+
var ExportEntityRefSchema = discriminatedUnion("kind", [
|
|
46129
|
+
object({
|
|
46130
|
+
kind: literal("device"),
|
|
46131
|
+
deviceId: string()
|
|
46132
|
+
}),
|
|
46133
|
+
object({
|
|
46134
|
+
kind: literal("action"),
|
|
46135
|
+
actionId: string().min(1)
|
|
46136
|
+
}),
|
|
46137
|
+
object({
|
|
46138
|
+
kind: literal("notifier"),
|
|
46139
|
+
targetId: string().min(1)
|
|
46140
|
+
})
|
|
46141
|
+
]);
|
|
46142
|
+
var ExposedEntitySchema = object({
|
|
46143
|
+
entity: ExportEntityRefSchema,
|
|
46144
|
+
exposedAs: string().optional()
|
|
46145
|
+
});
|
|
46146
|
+
var ExposeEntityInputSchema = object({
|
|
46147
|
+
instanceId: InstanceIdSchema$1,
|
|
46148
|
+
entity: ExportEntityRefSchema
|
|
46149
|
+
});
|
|
46150
|
+
var UnexposeEntityInputSchema = object({
|
|
46151
|
+
instanceId: InstanceIdSchema$1,
|
|
46152
|
+
entity: ExportEntityRefSchema
|
|
46153
|
+
});
|
|
46154
|
+
method(InstancePinSchema, DeviceExportStatusSchema), method(_void(), array(ExportInstanceSchema)), method(InstancePinSchema, array(DeviceKindSchema)), method(InstancePinSchema, array(ExposedDeviceSchema)), method(ExposeInputSchema, _void(), {
|
|
46155
|
+
kind: "mutation",
|
|
46156
|
+
auth: "admin"
|
|
46157
|
+
}), method(UnexposeInputSchema, _void(), {
|
|
46158
|
+
kind: "mutation",
|
|
46159
|
+
auth: "admin"
|
|
46160
|
+
}), method(SetExposedNameInputSchema, _void(), {
|
|
46161
|
+
kind: "mutation",
|
|
46162
|
+
auth: "admin"
|
|
46163
|
+
}), optionalMethod(_void(), array(ExportEntityKindSchema)), optionalMethod(InstancePinSchema, array(ExposedEntitySchema)), optionalMethod(ExposeEntityInputSchema, _void(), {
|
|
46164
|
+
kind: "mutation",
|
|
46165
|
+
auth: "admin"
|
|
46166
|
+
}), optionalMethod(UnexposeEntityInputSchema, _void(), {
|
|
46167
|
+
kind: "mutation",
|
|
46168
|
+
auth: "admin"
|
|
46169
|
+
});
|
|
46170
|
+
record(string(), string());
|
|
46005
46171
|
_enum([
|
|
46006
46172
|
"automation",
|
|
46007
46173
|
"action",
|
|
@@ -53783,144 +53949,6 @@ method(object({
|
|
|
53783
53949
|
kind: "mutation",
|
|
53784
53950
|
auth: "admin"
|
|
53785
53951
|
});
|
|
53786
|
-
/**
|
|
53787
|
-
* `device-export` — collection cap for addons that export camstack
|
|
53788
|
-
* devices to external ecosystems (HomeAssistant via MQTT discovery,
|
|
53789
|
-
* HomeKit/HAP, Alexa Smart Home, …).
|
|
53790
|
-
*
|
|
53791
|
-
* No `ecosystem` enum — the addon id identifies the export target.
|
|
53792
|
-
* Each addon owns its mapping logic in its own settings UI. The cap
|
|
53793
|
-
* exposes only the COMMON surface: link state, supported device
|
|
53794
|
-
* kinds (so the UI can filter the device picker), and per-device
|
|
53795
|
-
* expose/unexpose.
|
|
53796
|
-
*
|
|
53797
|
-
* INSTANCES. One export addon can serve several independent targets (a
|
|
53798
|
-
* HomeKit bridge, a Home Assistant broker). `listInstances` names them.
|
|
53799
|
-
* `instanceId` on a READ is optional: absent = the whole addon (linked if any
|
|
53800
|
-
* enabled instance is, `exposedDeviceCount` = distinct devices, `setup` = the
|
|
53801
|
-
* default instance's); present = that instance; an id the provider does not
|
|
53802
|
-
* serve is refused with `ExportInstanceUnknownError` (`export-instance-unknown`),
|
|
53803
|
-
* never answered empty. `instanceId` on a WRITE is REQUIRED: a membership
|
|
53804
|
-
* change always names the target it changes. A single-instance provider
|
|
53805
|
-
* accepts an absent id on a read or its own id, and refuses any other.
|
|
53806
|
-
*/
|
|
53807
|
-
/** Which instance of an export addon a call addresses. Absent on a read = the whole addon. */
|
|
53808
|
-
var InstanceIdSchema$1 = string().min(1);
|
|
53809
|
-
var InstancePinSchema = object({ instanceId: InstanceIdSchema$1.optional() });
|
|
53810
|
-
/** One independent export target of an addon. */
|
|
53811
|
-
var ExportInstanceSchema = object({
|
|
53812
|
-
instanceId: InstanceIdSchema$1,
|
|
53813
|
-
name: string(),
|
|
53814
|
-
enabled: boolean(),
|
|
53815
|
-
kind: string().optional()
|
|
53816
|
-
});
|
|
53817
|
-
var LinkStateSchema = _enum([
|
|
53818
|
-
"unlinked",
|
|
53819
|
-
"linked",
|
|
53820
|
-
"error"
|
|
53821
|
-
]);
|
|
53822
|
-
/**
|
|
53823
|
-
* A single label/value row surfaced in the export panel's "Setup"
|
|
53824
|
-
* section. Rendered with a copy-to-clipboard button. `secret: true`
|
|
53825
|
-
* rows are masked by default with a reveal toggle (client ids,
|
|
53826
|
-
* secrets, …).
|
|
53827
|
-
*/
|
|
53828
|
-
var ExportSetupFieldSchema = object({
|
|
53829
|
-
label: string(),
|
|
53830
|
-
value: string(),
|
|
53831
|
-
/** Mask the value by default + render a reveal toggle (client id, secrets). */
|
|
53832
|
-
secret: boolean().optional()
|
|
53833
|
-
});
|
|
53834
|
-
/**
|
|
53835
|
-
* Generic, addon-agnostic pairing/account block. Any export addon can
|
|
53836
|
-
* surface a scannable QR, a set of copyable label/value rows, and a
|
|
53837
|
-
* free-form operator note — the `DeviceExportPanel` renders whatever
|
|
53838
|
-
* the provider supplies and skips the section entirely when `setup`
|
|
53839
|
-
* is unset.
|
|
53840
|
-
*/
|
|
53841
|
-
var ExportSetupSchema = object({
|
|
53842
|
-
/** A string to render as a scannable QR — HAP `X-HM://…` URI, a pairing URL, etc. Omitted when there's nothing to scan. */
|
|
53843
|
-
qr: string().optional(),
|
|
53844
|
-
/** Label/value rows shown with a copy button (HAP setup code, OAuth URLs, client id, linked-account count, …). */
|
|
53845
|
-
fields: array(ExportSetupFieldSchema).readonly().optional(),
|
|
53846
|
-
/** Free-form operator instructions rendered above the fields. */
|
|
53847
|
-
note: string().optional()
|
|
53848
|
-
});
|
|
53849
|
-
var DeviceExportStatusSchema = object({
|
|
53850
|
-
linkState: LinkStateSchema,
|
|
53851
|
-
exposedDeviceCount: number$1(),
|
|
53852
|
-
error: string().optional(),
|
|
53853
|
-
/**
|
|
53854
|
-
* Optional pairing/account info the panel renders in a generic
|
|
53855
|
-
* "Setup" section. Addon-agnostic — the addon id identifies the
|
|
53856
|
-
* export target, never an `ecosystem` key here.
|
|
53857
|
-
*/
|
|
53858
|
-
setup: ExportSetupSchema.optional()
|
|
53859
|
-
});
|
|
53860
|
-
var DeviceKindSchema = string();
|
|
53861
|
-
var ExposedDeviceSchema = object({
|
|
53862
|
-
deviceId: string(),
|
|
53863
|
-
exposedAs: string().optional(),
|
|
53864
|
-
capabilities: array(string()).optional()
|
|
53865
|
-
});
|
|
53866
|
-
var ExposeInputSchema = object({
|
|
53867
|
-
instanceId: InstanceIdSchema$1,
|
|
53868
|
-
deviceId: string(),
|
|
53869
|
-
capabilities: array(string()).optional()
|
|
53870
|
-
});
|
|
53871
|
-
var UnexposeInputSchema = object({
|
|
53872
|
-
instanceId: InstanceIdSchema$1,
|
|
53873
|
-
deviceId: string()
|
|
53874
|
-
});
|
|
53875
|
-
/**
|
|
53876
|
-
* What an exporter may expose besides devices (D968). An action and a
|
|
53877
|
-
* notification target are LIST ENTRIES, never devices (D954): they enter an
|
|
53878
|
-
* exporter's own selection, not the device registry.
|
|
53879
|
-
*/
|
|
53880
|
-
var ExportEntityKindSchema = _enum([
|
|
53881
|
-
"device",
|
|
53882
|
-
"action",
|
|
53883
|
-
"notifier"
|
|
53884
|
-
]);
|
|
53885
|
-
var ExportEntityRefSchema = discriminatedUnion("kind", [
|
|
53886
|
-
object({
|
|
53887
|
-
kind: literal("device"),
|
|
53888
|
-
deviceId: string()
|
|
53889
|
-
}),
|
|
53890
|
-
object({
|
|
53891
|
-
kind: literal("action"),
|
|
53892
|
-
actionId: string().min(1)
|
|
53893
|
-
}),
|
|
53894
|
-
object({
|
|
53895
|
-
kind: literal("notifier"),
|
|
53896
|
-
targetId: string().min(1)
|
|
53897
|
-
})
|
|
53898
|
-
]);
|
|
53899
|
-
var ExposedEntitySchema = object({
|
|
53900
|
-
entity: ExportEntityRefSchema,
|
|
53901
|
-
exposedAs: string().optional()
|
|
53902
|
-
});
|
|
53903
|
-
var ExposeEntityInputSchema = object({
|
|
53904
|
-
instanceId: InstanceIdSchema$1,
|
|
53905
|
-
entity: ExportEntityRefSchema
|
|
53906
|
-
});
|
|
53907
|
-
var UnexposeEntityInputSchema = object({
|
|
53908
|
-
instanceId: InstanceIdSchema$1,
|
|
53909
|
-
entity: ExportEntityRefSchema
|
|
53910
|
-
});
|
|
53911
|
-
method(InstancePinSchema, DeviceExportStatusSchema), method(_void(), array(ExportInstanceSchema)), method(InstancePinSchema, array(DeviceKindSchema)), method(InstancePinSchema, array(ExposedDeviceSchema)), method(ExposeInputSchema, _void(), {
|
|
53912
|
-
kind: "mutation",
|
|
53913
|
-
auth: "admin"
|
|
53914
|
-
}), method(UnexposeInputSchema, _void(), {
|
|
53915
|
-
kind: "mutation",
|
|
53916
|
-
auth: "admin"
|
|
53917
|
-
}), optionalMethod(_void(), array(ExportEntityKindSchema)), optionalMethod(InstancePinSchema, array(ExposedEntitySchema)), optionalMethod(ExposeEntityInputSchema, _void(), {
|
|
53918
|
-
kind: "mutation",
|
|
53919
|
-
auth: "admin"
|
|
53920
|
-
}), optionalMethod(UnexposeEntityInputSchema, _void(), {
|
|
53921
|
-
kind: "mutation",
|
|
53922
|
-
auth: "admin"
|
|
53923
|
-
});
|
|
53924
53952
|
var DeviceAliasSchema = string().max(64).regex(/^[a-z][a-z0-9_]*$/);
|
|
53925
53953
|
var DeviceTemplateSchema = string().min(1).max(4096);
|
|
53926
53954
|
/** One value a caller hands the renderer for `thisDevice`. */
|
|
@@ -58775,6 +58803,128 @@ var StateLookSchema = object({
|
|
|
58775
58803
|
background: _enum(HERO_BACKGROUNDS),
|
|
58776
58804
|
animation: HeroAnimationSchema
|
|
58777
58805
|
});
|
|
58806
|
+
/** A string in both languages, as the cap vocabulary writes it (D920): no `t()` in the model. */
|
|
58807
|
+
var HeroTextSchema = object({
|
|
58808
|
+
en: string(),
|
|
58809
|
+
it: string()
|
|
58810
|
+
});
|
|
58811
|
+
/**
|
|
58812
|
+
* The ONE measurement a simple sensor shows (card wave, phase 1).
|
|
58813
|
+
*
|
|
58814
|
+
* A sensor that measures a single quantity (a temperature, a humidity, a power,
|
|
58815
|
+
* a contact, a text state) is drawn as that reading, once, big, inside a scene
|
|
58816
|
+
* whose motion says what the number means: heat rising when hot, flakes when
|
|
58817
|
+
* cold, a wire flowing at the speed of the power, a ring while a window is
|
|
58818
|
+
* open. Everything the card draws is decided here; a client only paints it.
|
|
58819
|
+
*/
|
|
58820
|
+
var HERO_MEASUREMENT_QUANTITIES = [
|
|
58821
|
+
"temperature",
|
|
58822
|
+
"humidity",
|
|
58823
|
+
"power",
|
|
58824
|
+
"contact",
|
|
58825
|
+
"text"
|
|
58826
|
+
];
|
|
58827
|
+
/** How a temperature reads to a person; drives the heat or the cold scene. */
|
|
58828
|
+
var HERO_MEASUREMENT_BANDS = [
|
|
58829
|
+
"hot",
|
|
58830
|
+
"mild",
|
|
58831
|
+
"cold"
|
|
58832
|
+
];
|
|
58833
|
+
/** `updated` = the value was last read then ("2 min ago"); `changed` = it has held since then ("for 12 min"). */
|
|
58834
|
+
var HERO_MEASUREMENT_SINCE_KINDS = ["updated", "changed"];
|
|
58835
|
+
var HeroMeasurementReadingSchema = object({
|
|
58836
|
+
value: number$1(),
|
|
58837
|
+
quantity: ReadingQuantitySchema
|
|
58838
|
+
});
|
|
58839
|
+
var HeroMeasurementSchema = object({
|
|
58840
|
+
quantity: _enum(HERO_MEASUREMENT_QUANTITIES),
|
|
58841
|
+
reading: HeroMeasurementReadingSchema.nullable(),
|
|
58842
|
+
icon: IconKeySchema.nullable(),
|
|
58843
|
+
value: HeroTextSchema,
|
|
58844
|
+
unit: string().nullable(),
|
|
58845
|
+
band: _enum(HERO_MEASUREMENT_BANDS).nullable(),
|
|
58846
|
+
level: number$1().min(0).max(1).nullable(),
|
|
58847
|
+
word: HeroTextSchema,
|
|
58848
|
+
tone: _enum(HERO_TONES),
|
|
58849
|
+
since: number$1().nullable(),
|
|
58850
|
+
sinceKind: _enum(HERO_MEASUREMENT_SINCE_KINDS),
|
|
58851
|
+
historyKey: string().nullable()
|
|
58852
|
+
});
|
|
58853
|
+
var same$2 = (text) => t(text, text);
|
|
58854
|
+
var clamp01$1 = (n) => Math.min(1, Math.max(0, n));
|
|
58855
|
+
var trimmed = (n, digits) => String(Number(n.toFixed(digits)));
|
|
58856
|
+
function temperatureBand(celsius) {
|
|
58857
|
+
if (celsius < 12) return "cold";
|
|
58858
|
+
if (celsius > 28) return "hot";
|
|
58859
|
+
return "mild";
|
|
58860
|
+
}
|
|
58861
|
+
var BAND_WORD = {
|
|
58862
|
+
hot: t("Hot", "Caldo"),
|
|
58863
|
+
mild: t("Normal", "Normale"),
|
|
58864
|
+
cold: t("Cold", "Freddo")
|
|
58865
|
+
};
|
|
58866
|
+
var BAND_TONE = {
|
|
58867
|
+
hot: "warning",
|
|
58868
|
+
mild: "muted",
|
|
58869
|
+
cold: "info"
|
|
58870
|
+
};
|
|
58871
|
+
function temperatureMeasurement(celsius, since) {
|
|
58872
|
+
const band = temperatureBand(celsius);
|
|
58873
|
+
return {
|
|
58874
|
+
quantity: "temperature",
|
|
58875
|
+
reading: {
|
|
58876
|
+
value: celsius,
|
|
58877
|
+
quantity: "temperature"
|
|
58878
|
+
},
|
|
58879
|
+
icon: "thermometer",
|
|
58880
|
+
value: same$2(trimmed(celsius, 1)),
|
|
58881
|
+
unit: "°C",
|
|
58882
|
+
band,
|
|
58883
|
+
level: null,
|
|
58884
|
+
word: BAND_WORD[band],
|
|
58885
|
+
tone: BAND_TONE[band],
|
|
58886
|
+
since,
|
|
58887
|
+
sinceKind: "updated",
|
|
58888
|
+
historyKey: "cap:temperature-sensor.temperature"
|
|
58889
|
+
};
|
|
58890
|
+
}
|
|
58891
|
+
function humidityMeasurement(percent, since) {
|
|
58892
|
+
const dry = percent < 30;
|
|
58893
|
+
const humid = percent > 70;
|
|
58894
|
+
return {
|
|
58895
|
+
quantity: "humidity",
|
|
58896
|
+
reading: {
|
|
58897
|
+
value: percent,
|
|
58898
|
+
quantity: "humidity"
|
|
58899
|
+
},
|
|
58900
|
+
icon: "droplets",
|
|
58901
|
+
value: same$2(String(Math.round(percent))),
|
|
58902
|
+
unit: "%",
|
|
58903
|
+
band: null,
|
|
58904
|
+
level: clamp01$1(percent / 100),
|
|
58905
|
+
word: dry ? t("Dry", "Secco") : humid ? t("Humid", "Umido") : t("Normal", "Normale"),
|
|
58906
|
+
tone: dry || humid ? "warning" : "info",
|
|
58907
|
+
since,
|
|
58908
|
+
sinceKind: "updated",
|
|
58909
|
+
historyKey: "cap:humidity-sensor.humidity"
|
|
58910
|
+
};
|
|
58911
|
+
}
|
|
58912
|
+
function textMeasurement(text, since) {
|
|
58913
|
+
return {
|
|
58914
|
+
quantity: "text",
|
|
58915
|
+
reading: null,
|
|
58916
|
+
icon: null,
|
|
58917
|
+
value: same$2(text),
|
|
58918
|
+
unit: null,
|
|
58919
|
+
band: null,
|
|
58920
|
+
level: null,
|
|
58921
|
+
word: t("Changed", "Cambiato"),
|
|
58922
|
+
tone: "muted",
|
|
58923
|
+
since,
|
|
58924
|
+
sinceKind: "updated",
|
|
58925
|
+
historyKey: null
|
|
58926
|
+
};
|
|
58927
|
+
}
|
|
58778
58928
|
/** The scene as the model carries it. `null` = the device did not say (never a guess). */
|
|
58779
58929
|
var HeroSceneSchema = object({
|
|
58780
58930
|
id: _enum([
|
|
@@ -58826,11 +58976,6 @@ var HeroSceneSchema = object({
|
|
|
58826
58976
|
});
|
|
58827
58977
|
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.HeatPump, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Gateway;
|
|
58828
58978
|
DeviceRole.Siren, DeviceRole.Floodlight, DeviceRole.Spotlight, DeviceRole.PirSensor, DeviceRole.Chime, DeviceRole.Autotrack, DeviceRole.Nightvision, DeviceRole.PrivacyMask, DeviceRole.Doorbell, DeviceRole.CoverBlind, DeviceRole.CoverShutter, DeviceRole.CoverAwning, DeviceRole.CoverCurtain, DeviceRole.CoverGarage, DeviceRole.CoverGate, DeviceRole.CoverDoor, DeviceRole.CoverWindow, DeviceRole.BinaryHelper, DeviceRole.Outlet, DeviceRole.SwitchHeater, DeviceRole.SwitchFan, DeviceRole.ClimateAc, DeviceRole.ClimateThermostat, DeviceRole.ClimateFloor, DeviceRole.ClimateRadiator, DeviceRole.ClimateHeater, DeviceRole.ClimateHeatPumpCircuit, DeviceRole.MotionSensor, DeviceRole.ContactSensor, DeviceRole.LeakSensor, DeviceRole.SmokeSensor, DeviceRole.COSensor, DeviceRole.GasSensor, DeviceRole.TamperSensor, DeviceRole.VibrationSensor, DeviceRole.ConnectivitySensor, DeviceRole.SoundSensor, DeviceRole.BinarySensor, DeviceRole.TemperatureSensor, DeviceRole.HumiditySensor, DeviceRole.AmbientLightSensor, DeviceRole.PressureSensor, DeviceRole.WindSensor, DeviceRole.RainSensor, DeviceRole.UvSensor, DeviceRole.SolarRadiationSensor, DeviceRole.SoilMoistureSensor, DeviceRole.PowerSensor, DeviceRole.EnergySensor, DeviceRole.VoltageSensor, DeviceRole.CurrentSensor, DeviceRole.AirQualitySensor, DeviceRole.BatterySensor, DeviceRole.NumericSensor, DeviceRole.EnumSensor, DeviceRole.DateTimeSensor, DeviceRole.GenericSensor, DeviceRole.NumericControl, DeviceRole.SelectControl, DeviceRole.TextControl, DeviceRole.DateTimeControl, DeviceRole.MobilePushNotifier, DeviceRole.MessagingNotifier, DeviceRole.EmailNotifier, DeviceRole.GenericNotifier, DeviceRole.IrTransmitter;
|
|
58829
|
-
/** A string in both languages, as the cap vocabulary writes it (D920): no `t()` in the model. */
|
|
58830
|
-
var HeroTextSchema = object({
|
|
58831
|
-
en: string(),
|
|
58832
|
-
it: string()
|
|
58833
|
-
});
|
|
58834
58979
|
var HeroRowIdSchema = _enum([
|
|
58835
58980
|
"progress",
|
|
58836
58981
|
"run-for",
|
|
@@ -58936,6 +59081,25 @@ var HeroControlSchema = discriminatedUnion("kind", [
|
|
|
58936
59081
|
optionLabels: record(string(), HeroTextSchema).optional(),
|
|
58937
59082
|
call: HeroCallSchema,
|
|
58938
59083
|
valueArg: string()
|
|
59084
|
+
}),
|
|
59085
|
+
object({
|
|
59086
|
+
kind: literal("number"),
|
|
59087
|
+
id: string(),
|
|
59088
|
+
label: HeroTextSchema,
|
|
59089
|
+
value: number$1().nullable(),
|
|
59090
|
+
/** `null` = any number; the device rounds what it does not accept. */
|
|
59091
|
+
step: number$1().nullable(),
|
|
59092
|
+
unit: string(),
|
|
59093
|
+
call: HeroCallSchema,
|
|
59094
|
+
valueArg: string()
|
|
59095
|
+
}),
|
|
59096
|
+
object({
|
|
59097
|
+
kind: literal("text"),
|
|
59098
|
+
id: string(),
|
|
59099
|
+
label: HeroTextSchema,
|
|
59100
|
+
value: string().nullable(),
|
|
59101
|
+
call: HeroCallSchema,
|
|
59102
|
+
valueArg: string()
|
|
58939
59103
|
})
|
|
58940
59104
|
]);
|
|
58941
59105
|
/** Declared by its interface: a `z.infer` of one more icon union pushes the cap's inferred type past what the compiler can print. */
|
|
@@ -59137,6 +59301,11 @@ var HeroModelSchema = object({
|
|
|
59137
59301
|
timedRun: HeroTimedRunSlotSchema.nullable(),
|
|
59138
59302
|
powerSupply: HeroPowerSupplySlotSchema.nullable(),
|
|
59139
59303
|
rows: array(HeroRowSchema),
|
|
59304
|
+
/**
|
|
59305
|
+
* The ONE measurement of a simple sensor, drawn once inside the scene in place of
|
|
59306
|
+
* the caption, tiles and value chips. Absent = the card draws as before.
|
|
59307
|
+
*/
|
|
59308
|
+
measurement: HeroMeasurementSchema.optional(),
|
|
59140
59309
|
/** Ids of parts that actuate the device, hidden from a session that may not act on it. */
|
|
59141
59310
|
gated: array(string()),
|
|
59142
59311
|
provenance: array(HeroProvenanceSchema)
|
|
@@ -59208,7 +59377,13 @@ var HeroRowModelSchema = object({
|
|
|
59208
59377
|
* the call. Absent or empty = `primary` alone.
|
|
59209
59378
|
*/
|
|
59210
59379
|
extras: array(HeroControlSchema).max(2).optional(),
|
|
59211
|
-
trailing: HeroFactSchema.nullable()
|
|
59380
|
+
trailing: HeroFactSchema.nullable(),
|
|
59381
|
+
/**
|
|
59382
|
+
* The simple sensor's one reading (the hero's `measurement`): the row draws its value
|
|
59383
|
+
* at the right, the unit small, the quantity's icon in the mini-scene. Absent = an
|
|
59384
|
+
* older server or a device that is not a simple sensor: draw `trailing`.
|
|
59385
|
+
*/
|
|
59386
|
+
measurement: HeroMeasurementSchema.optional()
|
|
59212
59387
|
});
|
|
59213
59388
|
new Set([
|
|
59214
59389
|
"temperature",
|
|
@@ -77735,10 +77910,15 @@ getStatus: method(object({ deviceId: number$1() }), RecordingSignalStatusSchema)
|
|
|
77735
77910
|
*/
|
|
77736
77911
|
history: "none"
|
|
77737
77912
|
};
|
|
77738
|
-
var RemoteBindingSchema = object({ action:
|
|
77739
|
-
|
|
77740
|
-
|
|
77741
|
-
|
|
77913
|
+
var RemoteBindingSchema = object({ action: object({
|
|
77914
|
+
kind: literal("cap"),
|
|
77915
|
+
deviceId: number$1().int().nonnegative(),
|
|
77916
|
+
cap: string().min(1),
|
|
77917
|
+
method: string().min(1),
|
|
77918
|
+
args: record(string(), unknown()).optional(),
|
|
77919
|
+
/** The unit the person picked per arg (display only); `args` always hold the cap's own unit. */
|
|
77920
|
+
argUnits: record(string(), string().min(1)).optional()
|
|
77921
|
+
}) });
|
|
77742
77922
|
var RemoteCustomButtonSchema = object({
|
|
77743
77923
|
/** The slug after `custom:` in the role. */
|
|
77744
77924
|
key: string().refine(isRemoteCustomKey, { message: "a lowercase slug" }),
|
|
@@ -78728,7 +78908,7 @@ var sceneMonitorCapability = {
|
|
|
78728
78908
|
* instead of failing silently weeks later.
|
|
78729
78909
|
*
|
|
78730
78910
|
* Reachable from three surfaces on this one mutation: the scene card, a
|
|
78731
|
-
* notification button (an `onTrigger` sequence with a `kind:'
|
|
78911
|
+
* notification button (an `onTrigger` sequence with a `kind:'command'` step —
|
|
78732
78912
|
* no new Notification-Center code at all), and tRPC for scripts.
|
|
78733
78913
|
*/
|
|
78734
78914
|
resetScene: method(object({
|
|
@@ -85721,6 +85901,13 @@ function contribution(cap, schema, build) {
|
|
|
85721
85901
|
}
|
|
85722
85902
|
};
|
|
85723
85903
|
}
|
|
85904
|
+
/** The fragment, carrying the cap's single measurement when it has one. */
|
|
85905
|
+
function measured(fragment, measurement) {
|
|
85906
|
+
return measurement === void 0 ? fragment : {
|
|
85907
|
+
...fragment,
|
|
85908
|
+
measurement
|
|
85909
|
+
};
|
|
85910
|
+
}
|
|
85724
85911
|
function action(id, label, icon, cap, method, args = {}, emphasis = "normal", confirm = null) {
|
|
85725
85912
|
return {
|
|
85726
85913
|
id,
|
|
@@ -86995,10 +87182,26 @@ var controlContribution = contribution("control", ControlStatusSchema, (slice, c
|
|
|
86995
87182
|
};
|
|
86996
87183
|
});
|
|
86997
87184
|
var CONTROL_LABEL = t("Value", "Valore");
|
|
86998
|
-
/**
|
|
87185
|
+
/**
|
|
87186
|
+
* A number with known bounds is a slider, one without a number field, a choice a picker,
|
|
87187
|
+
* free text a text field; a date stays read-only.
|
|
87188
|
+
*/
|
|
86999
87189
|
function controlRows(slice) {
|
|
87000
87190
|
if (slice.kind === "numeric" && typeof slice.value === "number") {
|
|
87001
|
-
if (slice.min === void 0 || slice.max === void 0) return [
|
|
87191
|
+
if (slice.min === void 0 || slice.max === void 0) return [row$1("control", "sliders-horizontal", null, [{
|
|
87192
|
+
kind: "number",
|
|
87193
|
+
id: "control.value",
|
|
87194
|
+
label: CONTROL_LABEL,
|
|
87195
|
+
value: slice.value,
|
|
87196
|
+
step: slice.step ?? null,
|
|
87197
|
+
unit: "",
|
|
87198
|
+
call: {
|
|
87199
|
+
cap: "control",
|
|
87200
|
+
method: "setValue",
|
|
87201
|
+
args: { control: { kind: "numeric" } }
|
|
87202
|
+
},
|
|
87203
|
+
valueArg: "control.value"
|
|
87204
|
+
}])];
|
|
87002
87205
|
return [row$1("control", "sliders-horizontal", null, [{
|
|
87003
87206
|
kind: "slider",
|
|
87004
87207
|
id: "control.value",
|
|
@@ -87029,6 +87232,18 @@ function controlRows(slice) {
|
|
|
87029
87232
|
},
|
|
87030
87233
|
valueArg: "control.value"
|
|
87031
87234
|
}])];
|
|
87235
|
+
if (slice.kind === "text") return [row$1("control", "sliders-horizontal", null, [{
|
|
87236
|
+
kind: "text",
|
|
87237
|
+
id: "control.value",
|
|
87238
|
+
label: CONTROL_LABEL,
|
|
87239
|
+
value: typeof slice.value === "string" ? slice.value : null,
|
|
87240
|
+
call: {
|
|
87241
|
+
cap: "control",
|
|
87242
|
+
method: "setValue",
|
|
87243
|
+
args: { control: { kind: "text" } }
|
|
87244
|
+
},
|
|
87245
|
+
valueArg: "control.value"
|
|
87246
|
+
}])];
|
|
87032
87247
|
return [];
|
|
87033
87248
|
}
|
|
87034
87249
|
var SENSORS_FAMILY_CONTRIBUTIONS = {
|
|
@@ -87384,15 +87599,15 @@ function sensorFragment(value, id, icon, en, it, text) {
|
|
|
87384
87599
|
tiles: { right: [tile$1(en, it, text)] }
|
|
87385
87600
|
};
|
|
87386
87601
|
}
|
|
87387
|
-
var temperatureContribution = contribution("temperature-sensor", TemperatureSensorStatusSchema, (slice) => sensorFragment(slice?.temperature ?? null, "temperature", "thermometer", "Temperature", "Temperatura", formatDegrees(slice?.temperature ?? 0)));
|
|
87388
|
-
var humidityContribution = contribution("humidity-sensor", HumiditySensorStatusSchema, (slice) => sensorFragment(slice?.humidity ?? null, "humidity", "droplets", "Humidity", "Umidità", `${Math.round(slice?.humidity ?? 0)}%`));
|
|
87602
|
+
var temperatureContribution = contribution("temperature-sensor", TemperatureSensorStatusSchema, (slice) => measured(sensorFragment(slice?.temperature ?? null, "temperature", "thermometer", "Temperature", "Temperatura", formatDegrees(slice?.temperature ?? 0)), slice?.temperature == null ? void 0 : temperatureMeasurement(slice.temperature, slice.lastFetchedAt)));
|
|
87603
|
+
var humidityContribution = contribution("humidity-sensor", HumiditySensorStatusSchema, (slice) => measured(sensorFragment(slice?.humidity ?? null, "humidity", "droplets", "Humidity", "Umidità", `${Math.round(slice?.humidity ?? 0)}%`), slice?.humidity == null ? void 0 : humidityMeasurement(slice.humidity, slice.lastFetchedAt)));
|
|
87389
87604
|
var pressureContribution = contribution("pressure-sensor", PressureSensorStatusSchema, (slice) => sensorFragment(slice?.pressure ?? null, "pressure", "gauge", "Pressure", "Pressione", `${Math.round(slice?.pressure ?? 0)} hPa`));
|
|
87390
87605
|
var illuminanceContribution = contribution("ambient-light-sensor", AmbientLightSensorStatusSchema, (slice) => sensorFragment(slice?.illuminance ?? null, "illuminance", "sun", "Light", "Luce", `${Math.round(slice?.illuminance ?? 0)} lx`));
|
|
87391
87606
|
var numericContribution = contribution("numeric-sensor", NumericSensorStatusSchema, (slice) => sensorFragment(slice?.value ?? null, "reading", "gauge", "Value", "Valore", String(Number((slice?.value ?? 0).toFixed(2)))));
|
|
87392
87607
|
var enumContribution = contribution("enum-sensor", EnumSensorStatusSchema, (slice) => {
|
|
87393
87608
|
if (slice === void 0 || slice.value === "") return { reading: reading("sensor", "unknown") };
|
|
87394
87609
|
if (slice.timestamp === true) return { reading: reading("sensor", "on") };
|
|
87395
|
-
return sensorFragment(slice.value, "reading", "gauge", "State", "Stato", slice.value);
|
|
87610
|
+
return measured(sensorFragment(slice.value, "reading", "gauge", "State", "Stato", slice.value), textMeasurement(slice.value, slice.lastFetchedAt));
|
|
87396
87611
|
});
|
|
87397
87612
|
/** Index bands: the headline of an air-quality sensor is a word, not a number. */
|
|
87398
87613
|
function airQualityWord(aqi) {
|
|
@@ -90288,6 +90503,13 @@ Object.freeze({
|
|
|
90288
90503
|
access: "view",
|
|
90289
90504
|
role: "admin"
|
|
90290
90505
|
},
|
|
90506
|
+
"deviceExport.setExposedName": {
|
|
90507
|
+
capName: "device-export",
|
|
90508
|
+
capScope: "system",
|
|
90509
|
+
addonId: null,
|
|
90510
|
+
access: "create",
|
|
90511
|
+
role: "admin"
|
|
90512
|
+
},
|
|
90291
90513
|
"deviceExport.unexposeDevice": {
|
|
90292
90514
|
capName: "device-export",
|
|
90293
90515
|
capScope: "system",
|
|
@@ -98752,48 +98974,6 @@ Object.freeze({
|
|
|
98752
98974
|
role: "admin"
|
|
98753
98975
|
}
|
|
98754
98976
|
});
|
|
98755
|
-
/**
|
|
98756
|
-
* "Do" actions an operator can pick for a device — presentation-free.
|
|
98757
|
-
*
|
|
98758
|
-
* The wire shape stays `{ cap, method, args }`. Since D920 this module no
|
|
98759
|
-
* longer HOLDS a catalogue: {@link DEVICE_DO_ACTIONS} is a projection of the
|
|
98760
|
-
* cap vocabulary (`cap-vocabulary/`), the one cap-keyed map of every action
|
|
98761
|
-
* and trigger — so a picker built on this module and one built on
|
|
98762
|
-
* `actionsForDevice` (the vocabulary resolver) can never disagree about what
|
|
98763
|
-
* a device can do. Ids, baked args and the matching of saved steps are the
|
|
98764
|
-
* vocabulary's; labels here are its English labels.
|
|
98765
|
-
*
|
|
98766
|
-
* Shared by the admin NC Sequences / rule Do editor and Automations; the
|
|
98767
|
-
* viewer can reuse the same catalogue once its step editor catches up.
|
|
98768
|
-
*/
|
|
98769
|
-
function openArgKind(offer) {
|
|
98770
|
-
if (offer.kind === "number") return "number";
|
|
98771
|
-
if (offer.kind === "dynamic" && offer.valueKind === "number") return "number";
|
|
98772
|
-
if (offer.kind === "enum" && offer.values.every((v) => typeof v.value === "number")) return "number";
|
|
98773
|
-
return "string";
|
|
98774
|
-
}
|
|
98775
|
-
function projectOpenArg(arg) {
|
|
98776
|
-
return {
|
|
98777
|
-
key: arg.key,
|
|
98778
|
-
label: arg.label.en,
|
|
98779
|
-
kind: openArgKind(arg.offer),
|
|
98780
|
-
offer: arg.offer,
|
|
98781
|
-
...arg.optional === true ? { optional: true } : {}
|
|
98782
|
-
};
|
|
98783
|
-
}
|
|
98784
|
-
function projectAction(cap, action) {
|
|
98785
|
-
const open = action.openArgs ?? [];
|
|
98786
|
-
return {
|
|
98787
|
-
id: action.id,
|
|
98788
|
-
label: action.label.en,
|
|
98789
|
-
cap,
|
|
98790
|
-
method: action.method,
|
|
98791
|
-
args: action.args ?? {},
|
|
98792
|
-
...open.length > 0 ? { openArgs: open.map(projectOpenArg) } : {}
|
|
98793
|
-
};
|
|
98794
|
-
}
|
|
98795
|
-
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
98796
|
-
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.HeatPump, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Gateway;
|
|
98797
98977
|
DeviceFeature.BatteryOperated;
|
|
98798
98978
|
function bound(cap, methods = [], authority = "reported") {
|
|
98799
98979
|
return {
|
|
@@ -102239,6 +102419,15 @@ function systemEventKindsOfFamily(family) {
|
|
|
102239
102419
|
return NC_SYSTEM_EVENT_KIND_GROUP_SPECS.filter((g) => g.family === family).flatMap((g) => g.kinds);
|
|
102240
102420
|
}
|
|
102241
102421
|
NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
|
|
102422
|
+
new Set([
|
|
102423
|
+
"alarm.trigger",
|
|
102424
|
+
"alarm.disarm",
|
|
102425
|
+
"alarm.arm.home",
|
|
102426
|
+
"alarm.arm.away",
|
|
102427
|
+
"alarm.arm.night",
|
|
102428
|
+
"alarm.arm.vacation",
|
|
102429
|
+
"alarm.arm.custom_bypass"
|
|
102430
|
+
]);
|
|
102242
102431
|
/**
|
|
102243
102432
|
* WHICH WAY A BOOLEAN SENSOR MOVED — read off the one slice a sensor event
|
|
102244
102433
|
* persists (D640 "a sensor rule fires on the raise, the clear, or both").
|
|
@@ -103924,7 +104113,7 @@ function findSpec(id) {
|
|
|
103924
104113
|
function capsOfSpec(spec) {
|
|
103925
104114
|
switch (spec.kind) {
|
|
103926
104115
|
case "power-meter": return ["power-meter"];
|
|
103927
|
-
case "battery": return ["
|
|
104116
|
+
case "battery": return ["numeric-sensor", "power-meter"];
|
|
103928
104117
|
case "meter": return ["meter"];
|
|
103929
104118
|
case "numeric": return ["numeric-sensor"];
|
|
103930
104119
|
case "text": return ["enum-sensor"];
|
|
@@ -104027,11 +104216,9 @@ function computeSlices(spec, snapshot, options, now) {
|
|
|
104027
104216
|
const v = numberOf(voltage);
|
|
104028
104217
|
const a = numberOf(current);
|
|
104029
104218
|
return {
|
|
104030
|
-
|
|
104031
|
-
|
|
104032
|
-
|
|
104033
|
-
sleeping: false,
|
|
104034
|
-
lastUpdated: now
|
|
104219
|
+
numeric: {
|
|
104220
|
+
value: nullableOf(soc),
|
|
104221
|
+
lastFetchedAt: now
|
|
104035
104222
|
},
|
|
104036
104223
|
...w !== void 0 || v !== void 0 || a !== void 0 ? { powerMeter: {
|
|
104037
104224
|
...w !== void 0 ? { power: w * sign || 0 } : {},
|
|
@@ -104177,12 +104364,6 @@ var METER_CAP = meterCapability.name;
|
|
|
104177
104364
|
var NUMERIC_CAP = numericSensorCapability.name;
|
|
104178
104365
|
var ENUM_CAP = enumSensorCapability.name;
|
|
104179
104366
|
var POWER_COLD = { lastFetchedAt: 0 };
|
|
104180
|
-
var BATTERY_COLD = {
|
|
104181
|
-
level: null,
|
|
104182
|
-
charging: "unknown",
|
|
104183
|
-
sleeping: false,
|
|
104184
|
-
lastUpdated: 0
|
|
104185
|
-
};
|
|
104186
104367
|
var VALUE_COLD = {
|
|
104187
104368
|
value: null,
|
|
104188
104369
|
lastFetchedAt: 0
|
|
@@ -104230,6 +104411,7 @@ var EnpalSensorDevice = class extends BaseDevice {
|
|
|
104230
104411
|
id: `${this.integrationId}:${spec.id}`,
|
|
104231
104412
|
system: ENPAL_SYSTEM,
|
|
104232
104413
|
...spec.kind === "meter" || spec.kind === "numeric" ? { quantity: spec.quantity } : {},
|
|
104414
|
+
...spec.kind === "battery" ? { quantity: spec.level.quantity } : {},
|
|
104233
104415
|
...spec.kind === "text" && spec.timestamp === true ? { dateTimeShape: "date" } : {}
|
|
104234
104416
|
});
|
|
104235
104417
|
}
|
|
@@ -104279,7 +104461,6 @@ var EnpalSensorDevice = class extends BaseDevice {
|
|
|
104279
104461
|
energy: this.energyGuard.accept(kwh)
|
|
104280
104462
|
});
|
|
104281
104463
|
}
|
|
104282
|
-
if (slices.battery !== void 0) this.runtimeState.setCapState(BATTERY_CAP, slices.battery);
|
|
104283
104464
|
if (slices.meter !== void 0) {
|
|
104284
104465
|
const raw = slices.meter.value;
|
|
104285
104466
|
this.runtimeState.setCapState(METER_CAP, {
|
|
@@ -104296,7 +104477,8 @@ var EnpalSensorDevice = class extends BaseDevice {
|
|
|
104296
104477
|
this.registerPowerMeter();
|
|
104297
104478
|
return;
|
|
104298
104479
|
case "battery":
|
|
104299
|
-
this.
|
|
104480
|
+
this.retractBatteryCap();
|
|
104481
|
+
this.registerNumeric();
|
|
104300
104482
|
this.registerPowerMeter();
|
|
104301
104483
|
return;
|
|
104302
104484
|
case "meter":
|
|
@@ -104308,8 +104490,7 @@ var EnpalSensorDevice = class extends BaseDevice {
|
|
|
104308
104490
|
this.runtimeState.setCapState(ENUM_CAP, TEXT_COLD);
|
|
104309
104491
|
return;
|
|
104310
104492
|
case "numeric":
|
|
104311
|
-
this.
|
|
104312
|
-
this.runtimeState.setCapState(NUMERIC_CAP, VALUE_COLD);
|
|
104493
|
+
this.registerNumeric();
|
|
104313
104494
|
return;
|
|
104314
104495
|
}
|
|
104315
104496
|
}
|
|
@@ -104317,15 +104498,18 @@ var EnpalSensorDevice = class extends BaseDevice {
|
|
|
104317
104498
|
this.ctx.registerNativeCap(powerMeterCapability, { getStatus: async () => this.runtimeState.getCapState(POWER_CAP) ?? POWER_COLD });
|
|
104318
104499
|
this.runtimeState.setCapState(POWER_CAP, POWER_COLD);
|
|
104319
104500
|
}
|
|
104320
|
-
|
|
104321
|
-
this.ctx.registerNativeCap(
|
|
104322
|
-
|
|
104323
|
-
|
|
104324
|
-
|
|
104325
|
-
|
|
104326
|
-
|
|
104327
|
-
|
|
104328
|
-
|
|
104501
|
+
registerNumeric() {
|
|
104502
|
+
this.ctx.registerNativeCap(numericSensorCapability, { getStatus: async () => this.runtimeState.getCapState(NUMERIC_CAP) ?? VALUE_COLD });
|
|
104503
|
+
this.runtimeState.setCapState(NUMERIC_CAP, VALUE_COLD);
|
|
104504
|
+
}
|
|
104505
|
+
/**
|
|
104506
|
+
* The storage battery once registered the `battery` cap (#522). This process never
|
|
104507
|
+
* registers it, so the call retracts the binding a previous incarnation left on the hub
|
|
104508
|
+
* (`unregisterNativeCap`'s stale-retract path): a restored device stops answering
|
|
104509
|
+
* `battery` and no `battery` slice is written again.
|
|
104510
|
+
*/
|
|
104511
|
+
retractBatteryCap() {
|
|
104512
|
+
this.ctx.unregisterNativeCap?.(BATTERY_CAP);
|
|
104329
104513
|
}
|
|
104330
104514
|
};
|
|
104331
104515
|
//#endregion
|