@camstack/types 1.2.419 → 1.2.421
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon.js +1 -1
- package/dist/addon.mjs +1 -1
- package/dist/capabilities/composer.cap.d.ts +36 -0
- package/dist/capabilities/core-blocks.cap.d.ts +252 -0
- package/dist/capabilities/power-meter.cap.d.ts +1 -1
- package/dist/capabilities/running-state.cap.d.ts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +166 -1
- package/dist/client.mjs +166 -2
- package/dist/composition/composition.d.ts +12 -0
- package/dist/composition/helpers/appliance.d.ts +28 -0
- package/dist/composition/helpers/compile.d.ts +1 -1
- package/dist/composition/helpers/index.d.ts +2 -1
- package/dist/composition/helpers/save.d.ts +1 -1
- package/dist/composition/helpers/spec.d.ts +21 -1
- package/dist/{composition-OhpuespA.mjs → composition-B2rw5L29.mjs} +88 -3
- package/dist/{composition-re1aezX9.js → composition-B3Hkb6v7.js} +135 -2
- package/dist/device/appliance-export.d.ts +25 -0
- package/dist/device/cap-vocabulary/types.d.ts +10 -0
- package/dist/device/device-type.d.ts +8 -2
- package/dist/{err-msg-BXKzRBwg.mjs → err-msg-DIorGYeC.mjs} +7 -1
- package/dist/{err-msg-BhVbr0NX.js → err-msg-U7lLUMNz.js} +7 -1
- package/dist/generated/customize-catalog.d.ts +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +318 -118
- package/dist/index.mjs +307 -119
- package/dist/node.js +2 -2
- package/dist/node.mjs +2 -2
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -699,8 +699,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
699
699
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
700
700
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
701
701
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
702
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
702
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
703
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
703
704
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
705
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
706
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
707
|
+
DeviceType["Washer"] = "washer";
|
|
708
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
709
|
+
DeviceType["Dryer"] = "dryer";
|
|
704
710
|
return DeviceType;
|
|
705
711
|
}({});
|
|
706
712
|
zod.z.enum(["new-session", "step-up"]);
|
|
@@ -26236,6 +26242,164 @@ method(zod.z.object({
|
|
|
26236
26242
|
auth: "protected"
|
|
26237
26243
|
});
|
|
26238
26244
|
//#endregion
|
|
26245
|
+
//#region src/device/container-primary-child.ts
|
|
26246
|
+
/**
|
|
26247
|
+
* WHICH child a container stands for — one definition, for every consumer.
|
|
26248
|
+
*
|
|
26249
|
+
* A CONTAINER device has no controllable surface of its own: it groups entity
|
|
26250
|
+
* children (a Gree air-conditioner grouping a climate child plus light, x-fan
|
|
26251
|
+
* and health switches). Everything that has to show or act on a container has
|
|
26252
|
+
* to answer the same question — which child IS the container — and until now
|
|
26253
|
+
* three places answered it separately:
|
|
26254
|
+
*
|
|
26255
|
+
* - `ui-library/device-controls/primary-child.ts` (admin-ui rendering)
|
|
26256
|
+
* - `addon-provider-homeassistant` PARENT_TYPE_PRIORITY (adoption)
|
|
26257
|
+
* - the viewer's own `container-primary.ts` (linked-devices panel)
|
|
26258
|
+
*
|
|
26259
|
+
* Each carried the same list and a comment asking the others to stay in sync.
|
|
26260
|
+
* This is that list, in the one package all of them already depend on.
|
|
26261
|
+
*
|
|
26262
|
+
* `ui-library` and the server's linked-devices expansion IMPORT it. Two
|
|
26263
|
+
* consumers cannot, and keep a checked copy instead: the viewer resolves
|
|
26264
|
+
* `@camstack/types` from its own `node_modules` (an installed release, where a
|
|
26265
|
+
* newly added export simply is not there), and the Home Assistant provider
|
|
26266
|
+
* expresses the same precedence over the `DeviceType` enum because it answers
|
|
26267
|
+
* a different question from the same ordering. `scripts/check-container-
|
|
26268
|
+
* priority-in-sync.ts` fails the build when either drifts — the comment that
|
|
26269
|
+
* used to ask for this could not.
|
|
26270
|
+
*
|
|
26271
|
+
* The rule has two halves and the ORDER matters: an operator's explicit pick
|
|
26272
|
+
* wins outright, and only in its absence does type priority decide. The pick is
|
|
26273
|
+
* keyed on the child's re-sync-stable `entityId`, not its numeric id, so it
|
|
26274
|
+
* survives a re-sync that reallocates ids.
|
|
26275
|
+
*/
|
|
26276
|
+
/**
|
|
26277
|
+
* Type priority, most→least "primary". An actuator (climate / lock / cover / …)
|
|
26278
|
+
* outranks a bare `switch` so a container's defining child wins over its
|
|
26279
|
+
* auxiliary switches. Unknown or absent types sort after every entry.
|
|
26280
|
+
*
|
|
26281
|
+
* NB: `siren` deliberately sits BELOW `switch` — it is a switch-family
|
|
26282
|
+
* actuator, and a camera's siren must not out-rank the thing the container is.
|
|
26283
|
+
*
|
|
26284
|
+
* These strings are matched against a child's `DeviceType` VALUE, so they must
|
|
26285
|
+
* equal the enum's string values.
|
|
26286
|
+
*/
|
|
26287
|
+
var CONTAINER_CHILD_PRIORITY = [
|
|
26288
|
+
"media-player",
|
|
26289
|
+
"alarm-panel",
|
|
26290
|
+
"thermostat",
|
|
26291
|
+
"climate",
|
|
26292
|
+
"humidifier",
|
|
26293
|
+
"water-heater",
|
|
26294
|
+
"lock",
|
|
26295
|
+
"cover",
|
|
26296
|
+
"valve",
|
|
26297
|
+
"fan",
|
|
26298
|
+
"vacuum",
|
|
26299
|
+
"lawn-mower",
|
|
26300
|
+
"washer",
|
|
26301
|
+
"dryer",
|
|
26302
|
+
"dishwasher",
|
|
26303
|
+
"light",
|
|
26304
|
+
"switch",
|
|
26305
|
+
"siren",
|
|
26306
|
+
"button",
|
|
26307
|
+
"control",
|
|
26308
|
+
"notifier",
|
|
26309
|
+
"script",
|
|
26310
|
+
"automation",
|
|
26311
|
+
"update",
|
|
26312
|
+
"presence",
|
|
26313
|
+
"weather",
|
|
26314
|
+
"image",
|
|
26315
|
+
"sensor"
|
|
26316
|
+
];
|
|
26317
|
+
/**
|
|
26318
|
+
* Roles that say what a container IS, most→least defining. Consulted BEFORE
|
|
26319
|
+
* type priority, because `DeviceType` cannot tell them apart: Home Assistant
|
|
26320
|
+
* maps a door contact, a battery level, a temperature reading and a "last seen"
|
|
26321
|
+
* timestamp all to `DeviceType.Sensor`. Measured on container 4127 — children
|
|
26322
|
+
* `battery-sensor`, `temperature-sensor`, `datetime-sensor`, `contact-sensor`
|
|
26323
|
+
* and a role-less `button` — the type list ranked `button` above `sensor` and
|
|
26324
|
+
* the container stood for its "Identifica" button instead of the door contact
|
|
26325
|
+
* it is named after.
|
|
26326
|
+
*
|
|
26327
|
+
* Only STATE-DEFINING roles belong here. A diagnostic reading (battery,
|
|
26328
|
+
* temperature, humidity, signal, last-seen) is never what a container is, so
|
|
26329
|
+
* they are deliberately absent and fall through to type priority.
|
|
26330
|
+
*/
|
|
26331
|
+
var CONTAINER_CHILD_ROLE_PRIORITY = [
|
|
26332
|
+
"contact-sensor",
|
|
26333
|
+
"motion-sensor",
|
|
26334
|
+
"occupancy-sensor",
|
|
26335
|
+
"smoke-sensor",
|
|
26336
|
+
"co-sensor",
|
|
26337
|
+
"gas-sensor",
|
|
26338
|
+
"leak-sensor",
|
|
26339
|
+
"vibration-sensor",
|
|
26340
|
+
"tamper-sensor",
|
|
26341
|
+
"sound-sensor"
|
|
26342
|
+
];
|
|
26343
|
+
/**
|
|
26344
|
+
* NOT in the list, deliberately: `binary-sensor` and `binary-helper`. They are
|
|
26345
|
+
* GENERIC — they say "this reports a boolean", not what the container is — and
|
|
26346
|
+
* ranking them above type priority is a live regression, not a hypothetical:
|
|
26347
|
+
* container 1837 holds a real `lock` (features `['lock-open']`) alongside a
|
|
26348
|
+
* child named "Actuator" whose only role is `binary-sensor`, and the generic
|
|
26349
|
+
* role beat the lock. A role earns a place here by naming a SUBJECT (a contact,
|
|
26350
|
+
* a leak, smoke), never by naming a datatype.
|
|
26351
|
+
*/
|
|
26352
|
+
function roleRank(role) {
|
|
26353
|
+
if (role === void 0) return CONTAINER_CHILD_ROLE_PRIORITY.length;
|
|
26354
|
+
const i = CONTAINER_CHILD_ROLE_PRIORITY.indexOf(role);
|
|
26355
|
+
return i === -1 ? CONTAINER_CHILD_ROLE_PRIORITY.length : i;
|
|
26356
|
+
}
|
|
26357
|
+
function rank(type) {
|
|
26358
|
+
const i = CONTAINER_CHILD_PRIORITY.indexOf(type);
|
|
26359
|
+
return i === -1 ? CONTAINER_CHILD_PRIORITY.length : i;
|
|
26360
|
+
}
|
|
26361
|
+
/**
|
|
26362
|
+
* The child a container stands for: the operator's pick when it still exists,
|
|
26363
|
+
* else the highest-priority type. `null` for a childless container — a caller
|
|
26364
|
+
* must decide what an empty container means for it, rather than being handed a
|
|
26365
|
+
* child that is not there.
|
|
26366
|
+
*/
|
|
26367
|
+
/**
|
|
26368
|
+
* Two names for the same thing, compared the way an integration writes them.
|
|
26369
|
+
*
|
|
26370
|
+
* An exact case-insensitive match was not enough, and the failure was total
|
|
26371
|
+
* rather than marginal. An ESPHome shutter arrives as a container named
|
|
26372
|
+
* `Tapparella-Kitchen` whose children include the COVER, named `Tapparella
|
|
26373
|
+
* kitchen`, and a device-presence entity carrying the slug verbatim,
|
|
26374
|
+
* `tapparella-kitchen`. The slug matched the container exactly and the cover
|
|
26375
|
+
* did not, so the namesake tie-break handed the container to a connectivity
|
|
26376
|
+
* indicator — and the viewer's accessory panel, which correctly shows only
|
|
26377
|
+
* children with an actuating control, then rendered NOTHING. The operator saw
|
|
26378
|
+
* no shutters at all on kitchen, studio and both porch cameras (2026-09-22).
|
|
26379
|
+
*
|
|
26380
|
+
* `Markise` was the control case that proved the mechanism: there the cover
|
|
26381
|
+
* really is called exactly like its container, so it won and appeared.
|
|
26382
|
+
*
|
|
26383
|
+
* Separators are therefore normalised — `-`, `_` and whitespace are the same
|
|
26384
|
+
* character for this comparison, and runs of them collapse. The two candidates
|
|
26385
|
+
* then tie on the namesake and the decision falls through to `rank(type)`,
|
|
26386
|
+
* where `cover` is eighth and a `presence` entity is not listed at all. The
|
|
26387
|
+
* criterion keeps doing its job for a container whose child IS the namesake;
|
|
26388
|
+
* it stops being decided by which integration used a hyphen.
|
|
26389
|
+
*/
|
|
26390
|
+
function sameName(childName, containerName) {
|
|
26391
|
+
const flatten = (v) => v.toLowerCase().replace(/[-_\s]+/g, " ").trim();
|
|
26392
|
+
return flatten(childName) === flatten(containerName);
|
|
26393
|
+
}
|
|
26394
|
+
function resolveContainerPrimaryChild(children, overrideEntityId, containerName) {
|
|
26395
|
+
if (overrideEntityId !== void 0 && overrideEntityId !== null) {
|
|
26396
|
+
const picked = children.find((c) => c.stableId === overrideEntityId) ?? children.find((c) => c.entityId !== void 0 && c.entityId === overrideEntityId);
|
|
26397
|
+
if (picked !== void 0) return picked;
|
|
26398
|
+
}
|
|
26399
|
+
const namesake = (c) => containerName !== void 0 && containerName.length > 0 && c.name !== void 0 && sameName(c.name, containerName) ? 0 : 1;
|
|
26400
|
+
return [...children].toSorted((a, b) => roleRank(a.role) - roleRank(b.role) || namesake(a) - namesake(b) || rank(a.type) - rank(b.type))[0] ?? null;
|
|
26401
|
+
}
|
|
26402
|
+
//#endregion
|
|
26239
26403
|
//#region src/device/device-state-handle.ts
|
|
26240
26404
|
var DEVICE_STATE_EVENT_CATEGORY = "device.state-changed";
|
|
26241
26405
|
/**
|
|
@@ -32331,6 +32495,7 @@ exports.parseRetrainRevisionConflict = parseRetrainRevisionConflict;
|
|
|
32331
32495
|
exports.pickerForCondition = pickerForCondition;
|
|
32332
32496
|
exports.pickerForRuleClasses = pickerForRuleClasses;
|
|
32333
32497
|
exports.projectSubjectPath = projectSubjectPath;
|
|
32498
|
+
exports.resolveContainerPrimaryChild = resolveContainerPrimaryChild;
|
|
32334
32499
|
exports.resolveIconKey = resolveIconKey;
|
|
32335
32500
|
exports.resolveModeDelays = resolveModeDelays;
|
|
32336
32501
|
exports.retrainBoxIou = retrainBoxIou;
|
package/dist/client.mjs
CHANGED
|
@@ -698,8 +698,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
698
698
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
699
699
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
700
700
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
701
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
701
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
702
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
702
703
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
704
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
705
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
706
|
+
DeviceType["Washer"] = "washer";
|
|
707
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
708
|
+
DeviceType["Dryer"] = "dryer";
|
|
703
709
|
return DeviceType;
|
|
704
710
|
}({});
|
|
705
711
|
z.enum(["new-session", "step-up"]);
|
|
@@ -26235,6 +26241,164 @@ method(z.object({
|
|
|
26235
26241
|
auth: "protected"
|
|
26236
26242
|
});
|
|
26237
26243
|
//#endregion
|
|
26244
|
+
//#region src/device/container-primary-child.ts
|
|
26245
|
+
/**
|
|
26246
|
+
* WHICH child a container stands for — one definition, for every consumer.
|
|
26247
|
+
*
|
|
26248
|
+
* A CONTAINER device has no controllable surface of its own: it groups entity
|
|
26249
|
+
* children (a Gree air-conditioner grouping a climate child plus light, x-fan
|
|
26250
|
+
* and health switches). Everything that has to show or act on a container has
|
|
26251
|
+
* to answer the same question — which child IS the container — and until now
|
|
26252
|
+
* three places answered it separately:
|
|
26253
|
+
*
|
|
26254
|
+
* - `ui-library/device-controls/primary-child.ts` (admin-ui rendering)
|
|
26255
|
+
* - `addon-provider-homeassistant` PARENT_TYPE_PRIORITY (adoption)
|
|
26256
|
+
* - the viewer's own `container-primary.ts` (linked-devices panel)
|
|
26257
|
+
*
|
|
26258
|
+
* Each carried the same list and a comment asking the others to stay in sync.
|
|
26259
|
+
* This is that list, in the one package all of them already depend on.
|
|
26260
|
+
*
|
|
26261
|
+
* `ui-library` and the server's linked-devices expansion IMPORT it. Two
|
|
26262
|
+
* consumers cannot, and keep a checked copy instead: the viewer resolves
|
|
26263
|
+
* `@camstack/types` from its own `node_modules` (an installed release, where a
|
|
26264
|
+
* newly added export simply is not there), and the Home Assistant provider
|
|
26265
|
+
* expresses the same precedence over the `DeviceType` enum because it answers
|
|
26266
|
+
* a different question from the same ordering. `scripts/check-container-
|
|
26267
|
+
* priority-in-sync.ts` fails the build when either drifts — the comment that
|
|
26268
|
+
* used to ask for this could not.
|
|
26269
|
+
*
|
|
26270
|
+
* The rule has two halves and the ORDER matters: an operator's explicit pick
|
|
26271
|
+
* wins outright, and only in its absence does type priority decide. The pick is
|
|
26272
|
+
* keyed on the child's re-sync-stable `entityId`, not its numeric id, so it
|
|
26273
|
+
* survives a re-sync that reallocates ids.
|
|
26274
|
+
*/
|
|
26275
|
+
/**
|
|
26276
|
+
* Type priority, most→least "primary". An actuator (climate / lock / cover / …)
|
|
26277
|
+
* outranks a bare `switch` so a container's defining child wins over its
|
|
26278
|
+
* auxiliary switches. Unknown or absent types sort after every entry.
|
|
26279
|
+
*
|
|
26280
|
+
* NB: `siren` deliberately sits BELOW `switch` — it is a switch-family
|
|
26281
|
+
* actuator, and a camera's siren must not out-rank the thing the container is.
|
|
26282
|
+
*
|
|
26283
|
+
* These strings are matched against a child's `DeviceType` VALUE, so they must
|
|
26284
|
+
* equal the enum's string values.
|
|
26285
|
+
*/
|
|
26286
|
+
var CONTAINER_CHILD_PRIORITY = [
|
|
26287
|
+
"media-player",
|
|
26288
|
+
"alarm-panel",
|
|
26289
|
+
"thermostat",
|
|
26290
|
+
"climate",
|
|
26291
|
+
"humidifier",
|
|
26292
|
+
"water-heater",
|
|
26293
|
+
"lock",
|
|
26294
|
+
"cover",
|
|
26295
|
+
"valve",
|
|
26296
|
+
"fan",
|
|
26297
|
+
"vacuum",
|
|
26298
|
+
"lawn-mower",
|
|
26299
|
+
"washer",
|
|
26300
|
+
"dryer",
|
|
26301
|
+
"dishwasher",
|
|
26302
|
+
"light",
|
|
26303
|
+
"switch",
|
|
26304
|
+
"siren",
|
|
26305
|
+
"button",
|
|
26306
|
+
"control",
|
|
26307
|
+
"notifier",
|
|
26308
|
+
"script",
|
|
26309
|
+
"automation",
|
|
26310
|
+
"update",
|
|
26311
|
+
"presence",
|
|
26312
|
+
"weather",
|
|
26313
|
+
"image",
|
|
26314
|
+
"sensor"
|
|
26315
|
+
];
|
|
26316
|
+
/**
|
|
26317
|
+
* Roles that say what a container IS, most→least defining. Consulted BEFORE
|
|
26318
|
+
* type priority, because `DeviceType` cannot tell them apart: Home Assistant
|
|
26319
|
+
* maps a door contact, a battery level, a temperature reading and a "last seen"
|
|
26320
|
+
* timestamp all to `DeviceType.Sensor`. Measured on container 4127 — children
|
|
26321
|
+
* `battery-sensor`, `temperature-sensor`, `datetime-sensor`, `contact-sensor`
|
|
26322
|
+
* and a role-less `button` — the type list ranked `button` above `sensor` and
|
|
26323
|
+
* the container stood for its "Identifica" button instead of the door contact
|
|
26324
|
+
* it is named after.
|
|
26325
|
+
*
|
|
26326
|
+
* Only STATE-DEFINING roles belong here. A diagnostic reading (battery,
|
|
26327
|
+
* temperature, humidity, signal, last-seen) is never what a container is, so
|
|
26328
|
+
* they are deliberately absent and fall through to type priority.
|
|
26329
|
+
*/
|
|
26330
|
+
var CONTAINER_CHILD_ROLE_PRIORITY = [
|
|
26331
|
+
"contact-sensor",
|
|
26332
|
+
"motion-sensor",
|
|
26333
|
+
"occupancy-sensor",
|
|
26334
|
+
"smoke-sensor",
|
|
26335
|
+
"co-sensor",
|
|
26336
|
+
"gas-sensor",
|
|
26337
|
+
"leak-sensor",
|
|
26338
|
+
"vibration-sensor",
|
|
26339
|
+
"tamper-sensor",
|
|
26340
|
+
"sound-sensor"
|
|
26341
|
+
];
|
|
26342
|
+
/**
|
|
26343
|
+
* NOT in the list, deliberately: `binary-sensor` and `binary-helper`. They are
|
|
26344
|
+
* GENERIC — they say "this reports a boolean", not what the container is — and
|
|
26345
|
+
* ranking them above type priority is a live regression, not a hypothetical:
|
|
26346
|
+
* container 1837 holds a real `lock` (features `['lock-open']`) alongside a
|
|
26347
|
+
* child named "Actuator" whose only role is `binary-sensor`, and the generic
|
|
26348
|
+
* role beat the lock. A role earns a place here by naming a SUBJECT (a contact,
|
|
26349
|
+
* a leak, smoke), never by naming a datatype.
|
|
26350
|
+
*/
|
|
26351
|
+
function roleRank(role) {
|
|
26352
|
+
if (role === void 0) return CONTAINER_CHILD_ROLE_PRIORITY.length;
|
|
26353
|
+
const i = CONTAINER_CHILD_ROLE_PRIORITY.indexOf(role);
|
|
26354
|
+
return i === -1 ? CONTAINER_CHILD_ROLE_PRIORITY.length : i;
|
|
26355
|
+
}
|
|
26356
|
+
function rank(type) {
|
|
26357
|
+
const i = CONTAINER_CHILD_PRIORITY.indexOf(type);
|
|
26358
|
+
return i === -1 ? CONTAINER_CHILD_PRIORITY.length : i;
|
|
26359
|
+
}
|
|
26360
|
+
/**
|
|
26361
|
+
* The child a container stands for: the operator's pick when it still exists,
|
|
26362
|
+
* else the highest-priority type. `null` for a childless container — a caller
|
|
26363
|
+
* must decide what an empty container means for it, rather than being handed a
|
|
26364
|
+
* child that is not there.
|
|
26365
|
+
*/
|
|
26366
|
+
/**
|
|
26367
|
+
* Two names for the same thing, compared the way an integration writes them.
|
|
26368
|
+
*
|
|
26369
|
+
* An exact case-insensitive match was not enough, and the failure was total
|
|
26370
|
+
* rather than marginal. An ESPHome shutter arrives as a container named
|
|
26371
|
+
* `Tapparella-Kitchen` whose children include the COVER, named `Tapparella
|
|
26372
|
+
* kitchen`, and a device-presence entity carrying the slug verbatim,
|
|
26373
|
+
* `tapparella-kitchen`. The slug matched the container exactly and the cover
|
|
26374
|
+
* did not, so the namesake tie-break handed the container to a connectivity
|
|
26375
|
+
* indicator — and the viewer's accessory panel, which correctly shows only
|
|
26376
|
+
* children with an actuating control, then rendered NOTHING. The operator saw
|
|
26377
|
+
* no shutters at all on kitchen, studio and both porch cameras (2026-09-22).
|
|
26378
|
+
*
|
|
26379
|
+
* `Markise` was the control case that proved the mechanism: there the cover
|
|
26380
|
+
* really is called exactly like its container, so it won and appeared.
|
|
26381
|
+
*
|
|
26382
|
+
* Separators are therefore normalised — `-`, `_` and whitespace are the same
|
|
26383
|
+
* character for this comparison, and runs of them collapse. The two candidates
|
|
26384
|
+
* then tie on the namesake and the decision falls through to `rank(type)`,
|
|
26385
|
+
* where `cover` is eighth and a `presence` entity is not listed at all. The
|
|
26386
|
+
* criterion keeps doing its job for a container whose child IS the namesake;
|
|
26387
|
+
* it stops being decided by which integration used a hyphen.
|
|
26388
|
+
*/
|
|
26389
|
+
function sameName(childName, containerName) {
|
|
26390
|
+
const flatten = (v) => v.toLowerCase().replace(/[-_\s]+/g, " ").trim();
|
|
26391
|
+
return flatten(childName) === flatten(containerName);
|
|
26392
|
+
}
|
|
26393
|
+
function resolveContainerPrimaryChild(children, overrideEntityId, containerName) {
|
|
26394
|
+
if (overrideEntityId !== void 0 && overrideEntityId !== null) {
|
|
26395
|
+
const picked = children.find((c) => c.stableId === overrideEntityId) ?? children.find((c) => c.entityId !== void 0 && c.entityId === overrideEntityId);
|
|
26396
|
+
if (picked !== void 0) return picked;
|
|
26397
|
+
}
|
|
26398
|
+
const namesake = (c) => containerName !== void 0 && containerName.length > 0 && c.name !== void 0 && sameName(c.name, containerName) ? 0 : 1;
|
|
26399
|
+
return [...children].toSorted((a, b) => roleRank(a.role) - roleRank(b.role) || namesake(a) - namesake(b) || rank(a.type) - rank(b.type))[0] ?? null;
|
|
26400
|
+
}
|
|
26401
|
+
//#endregion
|
|
26238
26402
|
//#region src/device/device-state-handle.ts
|
|
26239
26403
|
var DEVICE_STATE_EVENT_CATEGORY = "device.state-changed";
|
|
26240
26404
|
/**
|
|
@@ -32237,4 +32401,4 @@ var TimelapseRuleSchema = TimelapseRuleInputSchema.extend({
|
|
|
32237
32401
|
updatedAt: z.number()
|
|
32238
32402
|
});
|
|
32239
32403
|
//#endregion
|
|
32240
|
-
export { APPLE_SA_TO_MACRO, AUDIO_MACRO_LABELS, AlarmArmModeSchema, CLIP_BROKER_PACED_RATES, COCO_TO_MACRO, CamProfileSchema, DEFAULT_TIMELAPSE_PREVIEW_TEXT, DEFINITIVE_DEVICE_REFUSALS, DEVICE_CERT_RENEW_WINDOW_DAYS, DEVICE_CERT_SIGNATURE, DEVICE_DEFINITIVE_REFUSALS_BEFORE_DELETE, DEVICE_REFRESH_REFUSAL_PREFIX, DEVICE_SIGNATURE_MESSAGE_VERSION, DeviceType, EVENTFUL_CAP_NAMES, EVENT_KIND_BY_CAP, EVENT_TAXONOMY, ICON_CATEGORIES, ICON_ENTRIES, ICON_KEYS, ICON_VIEWER_MODULES, IconKeySchema, LOCATION_ICON_FALLBACK, MACRO_LABELS, NC_ALARM_DELAY_MAX_SEC, NC_ALARM_SENSORS_MAX, NC_ALARM_SYSTEM_EVENT_KINDS, NC_ALARM_TRIGGERED_MAX_SEC, NC_BATTERY_CONSUMABLE_SYSTEM_EVENT_KINDS, NC_CAMERA_SCOPE_CAP_NAME, NC_CONSUMABLE_LOW_PERCENT_DEFAULT, NC_CONSUMABLE_LOW_PERCENT_MAX, NC_GROUPING_DEFAULT_SEC, NC_GROUPING_MAX_SEC, NC_GROUPING_MIN_SEC, NC_RULE_EDITOR_SECTION_ORDER, NC_RULE_KIND_SPECS, NC_SENSOR_TRANSITION_UNSUPPORTED_REASON, NC_SYSTEM_EVENT_CLASS_SPECS, NC_SYSTEM_EVENT_FAMILY_FILTERS, NC_SYSTEM_EVENT_KIND_GROUP_SPECS, NC_SYSTEM_EVENT_SUMMARY_FAMILIES, NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS, NC_TEMPLATE_VARS, NcAlarmConfigSchema, NcAlarmSensorsSchema, NcAlarmSettingsPatchSchema, NcHistoryEntrySchema, NcRuleLastRunsSchema, NodeDirectorySchema, RECORDING_EXPORT_MAX_READ_BYTES, RETRAIN_REVIEW_ADJUSTED_IOU, RETRAIN_REVIEW_MATCH_IOU, RETRAIN_REVIEW_STATUSES, RETRAIN_REVISION_CONFLICT, SystemMirror, TIMELAPSE_DENSE_FLOOR_SEC, TimelapseRuleSchema, YAMNET_TO_MACRO, alarmDeviceBlocksArming, alarmDeviceSecureOnArm, alarmPatchLanded, buildDeviceEnrollmentLink, buildDeviceSignatureMessage, buildSubjectPath, bundledCamstack, canonicalIconKey, classifyRetrainReview, conditionVisibleForKind, createSystemProxy, deviceRefusalFromMessage, droppedConditionsForKind, expandSystemEventClasses, iconCategoryLabel, iconEntry, iconsInCategory, isDefinitiveDeviceRefusal, isDrawableSubjectPath, isHeldBackTemplateVar, isIconKey, isSystemRuleKind, kindsForDiscriminator, knownValues, locationIconKey, nodePickerItems, packagePickerItems, paintHex, paletteResultSchema, parseDeviceEnrollmentLink, parseRetrainRevisionConflict, pickerForCondition, pickerForRuleClasses, projectSubjectPath, resolveIconKey, resolveModeDelays, retrainBoxIou, retrainRevisionConflictMessage, ruleDeviceCompatCapNames, ruleEditorSectionsForKind, ruleGroupingApplies, ruleKindOf, ruleKindSpec, ruleSeedForSection, searchIcons, sensorTransitionNeverFires, sensorTransitionOffered, stateLabel, subjectPathSampleFromBox, subjectPathSvgPoints, summarizeReview, systemEventClassKinds, systemEventClassesFor, systemEventDeliveryProblems, systemEventFilterAppliesToAnyKind, systemEventKindsOfFamily, systemFamilyOfKind, templateCarriesSummary, templateVarDeliveryApplies, templateVarKindApplies, templateVarSystemEventApplies, withSystemEventClasses };
|
|
32404
|
+
export { APPLE_SA_TO_MACRO, AUDIO_MACRO_LABELS, AlarmArmModeSchema, CLIP_BROKER_PACED_RATES, COCO_TO_MACRO, CamProfileSchema, DEFAULT_TIMELAPSE_PREVIEW_TEXT, DEFINITIVE_DEVICE_REFUSALS, DEVICE_CERT_RENEW_WINDOW_DAYS, DEVICE_CERT_SIGNATURE, DEVICE_DEFINITIVE_REFUSALS_BEFORE_DELETE, DEVICE_REFRESH_REFUSAL_PREFIX, DEVICE_SIGNATURE_MESSAGE_VERSION, DeviceType, EVENTFUL_CAP_NAMES, EVENT_KIND_BY_CAP, EVENT_TAXONOMY, ICON_CATEGORIES, ICON_ENTRIES, ICON_KEYS, ICON_VIEWER_MODULES, IconKeySchema, LOCATION_ICON_FALLBACK, MACRO_LABELS, NC_ALARM_DELAY_MAX_SEC, NC_ALARM_SENSORS_MAX, NC_ALARM_SYSTEM_EVENT_KINDS, NC_ALARM_TRIGGERED_MAX_SEC, NC_BATTERY_CONSUMABLE_SYSTEM_EVENT_KINDS, NC_CAMERA_SCOPE_CAP_NAME, NC_CONSUMABLE_LOW_PERCENT_DEFAULT, NC_CONSUMABLE_LOW_PERCENT_MAX, NC_GROUPING_DEFAULT_SEC, NC_GROUPING_MAX_SEC, NC_GROUPING_MIN_SEC, NC_RULE_EDITOR_SECTION_ORDER, NC_RULE_KIND_SPECS, NC_SENSOR_TRANSITION_UNSUPPORTED_REASON, NC_SYSTEM_EVENT_CLASS_SPECS, NC_SYSTEM_EVENT_FAMILY_FILTERS, NC_SYSTEM_EVENT_KIND_GROUP_SPECS, NC_SYSTEM_EVENT_SUMMARY_FAMILIES, NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS, NC_TEMPLATE_VARS, NcAlarmConfigSchema, NcAlarmSensorsSchema, NcAlarmSettingsPatchSchema, NcHistoryEntrySchema, NcRuleLastRunsSchema, NodeDirectorySchema, RECORDING_EXPORT_MAX_READ_BYTES, RETRAIN_REVIEW_ADJUSTED_IOU, RETRAIN_REVIEW_MATCH_IOU, RETRAIN_REVIEW_STATUSES, RETRAIN_REVISION_CONFLICT, SystemMirror, TIMELAPSE_DENSE_FLOOR_SEC, TimelapseRuleSchema, YAMNET_TO_MACRO, alarmDeviceBlocksArming, alarmDeviceSecureOnArm, alarmPatchLanded, buildDeviceEnrollmentLink, buildDeviceSignatureMessage, buildSubjectPath, bundledCamstack, canonicalIconKey, classifyRetrainReview, conditionVisibleForKind, createSystemProxy, deviceRefusalFromMessage, droppedConditionsForKind, expandSystemEventClasses, iconCategoryLabel, iconEntry, iconsInCategory, isDefinitiveDeviceRefusal, isDrawableSubjectPath, isHeldBackTemplateVar, isIconKey, isSystemRuleKind, kindsForDiscriminator, knownValues, locationIconKey, nodePickerItems, packagePickerItems, paintHex, paletteResultSchema, parseDeviceEnrollmentLink, parseRetrainRevisionConflict, pickerForCondition, pickerForRuleClasses, projectSubjectPath, resolveContainerPrimaryChild, resolveIconKey, resolveModeDelays, retrainBoxIou, retrainRevisionConflictMessage, ruleDeviceCompatCapNames, ruleEditorSectionsForKind, ruleGroupingApplies, ruleKindOf, ruleKindSpec, ruleSeedForSection, searchIcons, sensorTransitionNeverFires, sensorTransitionOffered, stateLabel, subjectPathSampleFromBox, subjectPathSvgPoints, summarizeReview, systemEventClassKinds, systemEventClassesFor, systemEventDeliveryProblems, systemEventFilterAppliesToAnyKind, systemEventKindsOfFamily, systemFamilyOfKind, templateCarriesSummary, templateVarDeliveryApplies, templateVarKindApplies, templateVarSystemEventApplies, withSystemEventClasses };
|
|
@@ -776,6 +776,18 @@ export declare const CompositionSchema: z.ZodObject<{
|
|
|
776
776
|
aggregate: typeof import("./index.js").AggregateReducerSchema;
|
|
777
777
|
members: z.ZodArray<typeof import("./index.js").HelperMemberSchema>;
|
|
778
778
|
active: z.ZodOptional<typeof import("./index.js").ActiveCriterionSchema>;
|
|
779
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
780
|
+
kind: z.ZodLiteral<'appliance'>;
|
|
781
|
+
templateId: z.ZodLiteral<typeof import("./index.js").APPLIANCE_TEMPLATE_ID>;
|
|
782
|
+
appliance: z.ZodEnum<{
|
|
783
|
+
washer: 'washer';
|
|
784
|
+
dryer: 'dryer';
|
|
785
|
+
dishwasher: 'dishwasher';
|
|
786
|
+
}>;
|
|
787
|
+
thresholdWatts: z.ZodNumber;
|
|
788
|
+
startDwellMs: z.ZodNumber;
|
|
789
|
+
stopDwellMs: z.ZodNumber;
|
|
790
|
+
member: typeof import("./index.js").HelperMemberSchema;
|
|
779
791
|
}, z.core.$strip>], "kind">>;
|
|
780
792
|
}, z.core.$strip>;
|
|
781
793
|
export type Composition = z.infer<typeof CompositionSchema>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
3
|
+
*
|
|
4
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
5
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
6
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
7
|
+
*
|
|
8
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
9
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
10
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
12
|
+
* can move later without moving the others.
|
|
13
|
+
*/
|
|
14
|
+
import { DeviceType } from '../../device/device-type.js';
|
|
15
|
+
import type { SourcePickRequest } from './source-pick.js';
|
|
16
|
+
export declare const APPLIANCE_TEMPLATE_ID: 'appliance';
|
|
17
|
+
export declare const APPLIANCE_KINDS: readonly ['washer', 'dryer', 'dishwasher'];
|
|
18
|
+
export type ApplianceKind = (typeof APPLIANCE_KINDS)[number];
|
|
19
|
+
export interface ApplianceDefaults {
|
|
20
|
+
readonly thresholdWatts: number;
|
|
21
|
+
readonly startDwellMs: number;
|
|
22
|
+
readonly stopDwellMs: number;
|
|
23
|
+
}
|
|
24
|
+
export declare const APPLIANCE_DEFAULTS: Readonly<Record<ApplianceKind, ApplianceDefaults>>;
|
|
25
|
+
export declare function applianceDeviceType(kind: ApplianceKind): DeviceType;
|
|
26
|
+
export declare function isApplianceKind(value: string): value is ApplianceKind;
|
|
27
|
+
/** The member step: one watts reading, from a sensor or from the plug itself. */
|
|
28
|
+
export declare function sourcePickForAppliance(): SourcePickRequest;
|
|
@@ -15,7 +15,7 @@ export interface HelperRefused {
|
|
|
15
15
|
readonly problems: readonly CompositionProblem[];
|
|
16
16
|
}
|
|
17
17
|
export type HelperCompileResult = HelperCompiled | HelperRefused;
|
|
18
|
-
/** Compile a
|
|
18
|
+
/** Compile a helper template to a new-device composition. Refusals are named. */
|
|
19
19
|
export declare function compileHelper(spec: HelperSpec): HelperCompileResult;
|
|
20
20
|
/** The built body, ignoring `helper`, so a save can demand one writer. */
|
|
21
21
|
export declare function sameHelperBody(stored: Composition, compiled: Composition): boolean;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { FAN_OUT_CONCURRENCY, LIGHT_SHARED_CAPS, type FanOutCall, type FanOutFailed, type FanOutMember, type FanOutMemberResult, type FanOutOk, type LightSharedCap, activeForReducer, fanOutTargets, reducerForActive, runFanOut, sharedColorModes, sharedLightCaps, } from './actuator.js';
|
|
2
2
|
export { type AggregateCounts, type AggregateEmpty, type AggregateOutcome, type AggregatePublish, type AggregateReadResult, type AggregateUnavailable, type AggregateValue, type EvaluateAggregateInput, evaluateAggregate, } from './aggregate.js';
|
|
3
|
+
export { APPLIANCE_DEFAULTS, APPLIANCE_KINDS, APPLIANCE_TEMPLATE_ID, type ApplianceDefaults, type ApplianceKind, applianceDeviceType, isApplianceKind, sourcePickForAppliance, } from './appliance.js';
|
|
3
4
|
export { type GroupTemplate, type HelperAccept, type HelperCompanion, GROUP_TEMPLATES, groupTemplate, } from './catalog.js';
|
|
4
5
|
export { type HelperCompileResult, type HelperCompiled, type HelperRefused, compileHelper, sameHelperBody, templateDeviceType, } from './compile.js';
|
|
5
6
|
export { type HelperMemberFact, helperSaveProblems, } from './save.js';
|
|
6
7
|
export { type SourcePick, type SourcePickAccept, type SourcePickHistory, type SourcePickRequest, sourcePickForTemplate, } from './source-pick.js';
|
|
7
|
-
export { ACTIVE_CRITERIA, AGGREGATE_REDUCERS, ActiveCriterionSchema, AggregateReducerSchema, BINARY_AGGREGATES, GROUP_TEMPLATE_IDS, GroupHelperSpecSchema, GroupTemplateIdSchema, HelperMemberSchema, HelperSpecSchema, MAX_HELPER_MEMBERS, NUMERIC_AGGREGATES, type ActiveCriterion, type AggregateReducer, type BinaryAggregate, type GroupHelperSpec, type GroupTemplateId, type HelperMember, type HelperSpec, type NumericAggregate, } from './spec.js';
|
|
8
|
+
export { ACTIVE_CRITERIA, AGGREGATE_REDUCERS, ActiveCriterionSchema, AggregateReducerSchema, BINARY_AGGREGATES, GROUP_TEMPLATE_IDS, ApplianceHelperSpecSchema, GroupHelperSpecSchema, GroupTemplateIdSchema, HelperMemberSchema, HelperSpecSchema, MAX_HELPER_MEMBERS, helperMembers, NUMERIC_AGGREGATES, type ActiveCriterion, type AggregateReducer, type BinaryAggregate, type ApplianceHelperSpec, type GroupHelperSpec, type GroupTemplateId, type HelperMember, type HelperSpec, type NumericAggregate, } from './spec.js';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Save-time checks a pure compile cannot make: the compiled features must be
|
|
3
3
|
* this spec's, and members that report a quantity must share one (D944 §4).
|
|
4
4
|
*/
|
|
5
|
-
import
|
|
5
|
+
import { DeviceType } from '../../device/device-type.js';
|
|
6
6
|
import type { ReadingQuantity } from '../../units/quantity.js';
|
|
7
7
|
import { type Composition } from '../composition.js';
|
|
8
8
|
import type { CompositionProblem } from '../composition-report.js';
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* features are a projection; the editor never edits the expression.
|
|
4
4
|
*/
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
+
import { APPLIANCE_TEMPLATE_ID } from './appliance.js';
|
|
6
7
|
import { CompositionSourceRefSchema } from '../source-ref.js';
|
|
7
8
|
/** A group may name more members than an expression call (the 16-arg cap). */
|
|
8
9
|
export declare const MAX_HELPER_MEMBERS: number;
|
|
@@ -39,5 +40,24 @@ export declare const GroupHelperSpecSchema: z.ZodObject<{
|
|
|
39
40
|
active: z.ZodOptional<typeof ActiveCriterionSchema>;
|
|
40
41
|
}>;
|
|
41
42
|
export type GroupHelperSpec = z.infer<typeof GroupHelperSpecSchema>;
|
|
42
|
-
export declare const
|
|
43
|
+
export declare const ApplianceHelperSpecSchema: z.ZodObject<{
|
|
44
|
+
kind: z.ZodLiteral<'appliance'>;
|
|
45
|
+
templateId: z.ZodLiteral<typeof APPLIANCE_TEMPLATE_ID>;
|
|
46
|
+
appliance: z.ZodEnum<{
|
|
47
|
+
washer: 'washer';
|
|
48
|
+
dryer: 'dryer';
|
|
49
|
+
dishwasher: 'dishwasher';
|
|
50
|
+
}>;
|
|
51
|
+
thresholdWatts: z.ZodNumber;
|
|
52
|
+
startDwellMs: z.ZodNumber;
|
|
53
|
+
stopDwellMs: z.ZodNumber;
|
|
54
|
+
member: typeof HelperMemberSchema;
|
|
55
|
+
}>;
|
|
56
|
+
export type ApplianceHelperSpec = z.infer<typeof ApplianceHelperSpecSchema>;
|
|
57
|
+
export declare const HelperSpecSchema: z.ZodDiscriminatedUnion<[
|
|
58
|
+
typeof GroupHelperSpecSchema,
|
|
59
|
+
typeof ApplianceHelperSpecSchema
|
|
60
|
+
], 'kind'>;
|
|
43
61
|
export type HelperSpec = z.infer<typeof HelperSpecSchema>;
|
|
62
|
+
/** Every member a helper reads. An appliance has one. */
|
|
63
|
+
export declare function helperMembers(spec: HelperSpec): readonly HelperMember[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as DeviceType, i as DeviceRole } from "./err-msg-
|
|
1
|
+
import { a as DeviceType, i as DeviceRole } from "./err-msg-DIorGYeC.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
//#region src/ffmpeg/invocation.ts
|
|
@@ -2160,6 +2160,78 @@ function evaluateExpressionSource(expr, bindingValues, now, opts) {
|
|
|
2160
2160
|
}
|
|
2161
2161
|
}
|
|
2162
2162
|
//#endregion
|
|
2163
|
+
//#region src/composition/helpers/appliance.ts
|
|
2164
|
+
/**
|
|
2165
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
2166
|
+
*
|
|
2167
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
2168
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
2169
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
2170
|
+
*
|
|
2171
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
2172
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
2173
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
2174
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
2175
|
+
* can move later without moving the others.
|
|
2176
|
+
*/
|
|
2177
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
2178
|
+
var APPLIANCE_KINDS = [
|
|
2179
|
+
"washer",
|
|
2180
|
+
"dryer",
|
|
2181
|
+
"dishwasher"
|
|
2182
|
+
];
|
|
2183
|
+
var START_DWELL_MS = 3e4;
|
|
2184
|
+
var STOP_DWELL_MS = 6e5;
|
|
2185
|
+
var THRESHOLD_WATTS = 5;
|
|
2186
|
+
var APPLIANCE_DEFAULTS = {
|
|
2187
|
+
washer: {
|
|
2188
|
+
thresholdWatts: THRESHOLD_WATTS,
|
|
2189
|
+
startDwellMs: START_DWELL_MS,
|
|
2190
|
+
stopDwellMs: STOP_DWELL_MS
|
|
2191
|
+
},
|
|
2192
|
+
dryer: {
|
|
2193
|
+
thresholdWatts: THRESHOLD_WATTS,
|
|
2194
|
+
startDwellMs: START_DWELL_MS,
|
|
2195
|
+
stopDwellMs: STOP_DWELL_MS
|
|
2196
|
+
},
|
|
2197
|
+
dishwasher: {
|
|
2198
|
+
thresholdWatts: THRESHOLD_WATTS,
|
|
2199
|
+
startDwellMs: START_DWELL_MS,
|
|
2200
|
+
stopDwellMs: STOP_DWELL_MS
|
|
2201
|
+
}
|
|
2202
|
+
};
|
|
2203
|
+
var DEVICE_TYPE = {
|
|
2204
|
+
washer: DeviceType.Washer,
|
|
2205
|
+
dryer: DeviceType.Dryer,
|
|
2206
|
+
dishwasher: DeviceType.Dishwasher
|
|
2207
|
+
};
|
|
2208
|
+
function applianceDeviceType(kind) {
|
|
2209
|
+
return DEVICE_TYPE[kind];
|
|
2210
|
+
}
|
|
2211
|
+
function isApplianceKind(value) {
|
|
2212
|
+
return APPLIANCE_KINDS.some((kind) => kind === value);
|
|
2213
|
+
}
|
|
2214
|
+
/** The member step: one watts reading, from a sensor or from the plug itself. */
|
|
2215
|
+
function sourcePickForAppliance() {
|
|
2216
|
+
return {
|
|
2217
|
+
purpose: "reading",
|
|
2218
|
+
multiple: false,
|
|
2219
|
+
max: 1,
|
|
2220
|
+
deviceTypes: [DeviceType.Sensor, DeviceType.Switch],
|
|
2221
|
+
accept: [{
|
|
2222
|
+
cap: "power-meter",
|
|
2223
|
+
fieldPath: "watts",
|
|
2224
|
+
valueKind: "number"
|
|
2225
|
+
}],
|
|
2226
|
+
history: {
|
|
2227
|
+
required: false,
|
|
2228
|
+
minRetentionMs: null
|
|
2229
|
+
},
|
|
2230
|
+
mustBindCaps: [],
|
|
2231
|
+
exclude: []
|
|
2232
|
+
};
|
|
2233
|
+
}
|
|
2234
|
+
//#endregion
|
|
2163
2235
|
//#region src/composition/source-ref.ts
|
|
2164
2236
|
/**
|
|
2165
2237
|
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
@@ -2237,7 +2309,20 @@ var GroupHelperSpecSchema = z.object({
|
|
|
2237
2309
|
/** Actuator groups only. Readings leave this unset. */
|
|
2238
2310
|
active: ActiveCriterionSchema.optional()
|
|
2239
2311
|
});
|
|
2240
|
-
var
|
|
2312
|
+
var ApplianceHelperSpecSchema = z.object({
|
|
2313
|
+
kind: z.literal("appliance"),
|
|
2314
|
+
templateId: z.literal(APPLIANCE_TEMPLATE_ID),
|
|
2315
|
+
appliance: z.enum(APPLIANCE_KINDS),
|
|
2316
|
+
thresholdWatts: z.number().positive(),
|
|
2317
|
+
startDwellMs: z.number().int().nonnegative(),
|
|
2318
|
+
stopDwellMs: z.number().int().nonnegative(),
|
|
2319
|
+
member: HelperMemberSchema
|
|
2320
|
+
});
|
|
2321
|
+
var HelperSpecSchema = z.discriminatedUnion("kind", [GroupHelperSpecSchema, ApplianceHelperSpecSchema]);
|
|
2322
|
+
/** Every member a helper reads. An appliance has one. */
|
|
2323
|
+
function helperMembers(spec) {
|
|
2324
|
+
return spec.kind === "group" ? spec.members : [spec.member];
|
|
2325
|
+
}
|
|
2241
2326
|
//#endregion
|
|
2242
2327
|
//#region src/composition/composition.ts
|
|
2243
2328
|
/**
|
|
@@ -2497,4 +2582,4 @@ function featureSources(feature) {
|
|
|
2497
2582
|
return featureFieldEntries(feature).map((e) => e.source);
|
|
2498
2583
|
}
|
|
2499
2584
|
//#endregion
|
|
2500
|
-
export {
|
|
2585
|
+
export { APPLIANCE_DEFAULTS as $, audioPlanFromEncodeProfile as $t, compositionFeatureEnabled as A, evaluateRose as At, ActiveCriterionSchema as B, evaluateSensorLevelEdge as Bt, CompositionTargetSchema as C, MAX_EXPRESSION_EVAL_STEPS as Ct, MAX_COMPOSITION_ITEMS as D, EXPRESSION_BUILTIN_NAMES as Dt, MAX_COMPOSITION_FIELDS_PER_FEATURE as E, EXPRESSION_BUILTINS as Et, featureFieldEntries as F, SOURCE_CAPS as Ft, GroupHelperSpecSchema as G, chooseFfmpegBinary as Gt, ApplianceHelperSpecSchema as H, sliceActiveValue as Ht, featureSources as I, SOURCE_CAP_ACTIVE_FIELD as It, HelperSpecSchema as J, getFfmpegArtifact as Jt, GroupTemplateIdSchema as K, ffmpegBinaryName as Kt, fieldReads as L, SOURCE_CAP_CHANGED_AT_FIELD as Lt, compositionReadKey as M, ExpressionEvalError as Mt, compositionSliceKey as N, ExpressionParseError as Nt, composedDeviceRef as O, disarmRoseMemory as Ot, compositionSourceKey as P, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as Pt, CompositionSourceRefSchema as Q, AUDIO_PRESETS as Qt, ACTIVE_CRITERIA as R, SOURCE_DEVICE_TYPES as Rt, CompositionSchema as S, MAX_EXPRESSION_CALL_ARGS as St, MAX_COMPOSITION_FEATURES as T, RESERVED_BINDING_NAMES as Tt, BINARY_AGGREGATES as U, sliceChangedAt as Ut, AggregateReducerSchema as V, isSourceCap as Vt, GROUP_TEMPLATE_IDS as W, FFMPEG_PATH_ENV as Wt, NUMERIC_AGGREGATES as X, canonicalHash as Xt, MAX_HELPER_MEMBERS as Y, getFfmpegDownloadUrl as Yt, helperMembers as Z, Fmp4BoxSplitter as Zt, CompositionFromSourceSchema as _, tokenize as _t, CUSTOMIZATION_BLOCK_NAME_PREFIX as a, isSoftwareDecode as an, EXPRESSION_INJECTED_NOW as at, CompositionNewTargetSchema as b, MAX_EXPRESSION_AST_NODES as bt, CompositionCodeSourceSchema as c, resolveStreamMaps as cn, evaluateExpressionSource as ct, CompositionExpressionSourceSchema as d, validateExpressionSource as dt, buildAudioArgs as en, APPLIANCE_KINDS as et, CompositionFeatureSchema as f, createExpressionScope as ft, CompositionForwardCommandSchema as g, parseExpression as gt, CompositionFieldsFeatureSchema as h, compileExpressionSafe as ht, COMPOSITION_ITEM_KEY_RE as i, invocationFromEncodeProfile as in, sourcePickForAppliance as it, compositionItemFieldPath as j, isStatefulBuiltin as jt, composedDeviceStableId as k, evaluateCount as kt, CompositionCommandTargetSchema as l, evaluateStatefulExpressionCall as lt, CompositionFieldSourceSchema as m, compileExpression as mt, COMPOSER_ADDON_ID as n, buildInputArgs as nn, applianceDeviceType as nt, CompositionAggregateSourceSchema as o, logBannerArgs as on, cloneStatefulExpressionMemory as ot, CompositionFieldReadSchema as p, evaluateAst as pt, HelperMemberSchema as q, FFMPEG_RELEASE as qt, COMPOSITION_ITEM_ARRAY_PATH as r, buildVideoArgs as rn, isApplianceKind as rt, CompositionBindingSchema as s, pickVideoEncoder as sn, createStatefulExpressionMemory as st, COMPOSED_DEVICE_STABLE_ID_PREFIX as t, buildFfmpegArgs as tn, APPLIANCE_TEMPLATE_ID as tt, CompositionExistingTargetSchema as u, toExpressionValue as ut, CompositionItemEntrySchema as v, EXPRESSION_COMPILE_CACHE_CAPACITY as vt, MAX_COMPOSITION_CODE_LENGTH as w, MAX_EXPRESSION_SOURCE_LENGTH as wt, CompositionPassthroughFeatureSchema as x, MAX_EXPRESSION_BINDINGS as xt, CompositionLiteralBindingSchema as y, EXPRESSION_IDENTIFIER_RE as yt, AGGREGATE_REDUCERS as z, evaluateSensorEdge as zt };
|