@camstack/types 1.2.300 → 1.2.303
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/automation/recipe.d.ts +2 -2
- package/dist/capabilities/core-blocks.cap.d.ts +17 -17
- package/dist/capabilities/device-admin-link-url.d.ts +2 -2
- package/dist/capabilities/device-admin-link.cap.d.ts +1 -1
- package/dist/capabilities/index.d.ts +2 -2
- package/dist/capabilities/local-network.cap.d.ts +1 -1
- package/dist/capabilities/notification-output.cap.d.ts +41 -0
- package/dist/capabilities/notification-rules.cap.d.ts +230 -0
- package/dist/device/device-do-actions.d.ts +57 -0
- package/dist/generated/addon-api.d.ts +14 -0
- package/dist/generated/method-access-map.d.ts +1 -1
- package/dist/generated/system-proxy.d.ts +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +545 -23
- package/dist/index.mjs +533 -24
- package/dist/interfaces/config-ui.d.ts +85 -1
- package/dist/notification/alarm-membership.d.ts +9 -0
- package/dist/notification/alarm-profiles.d.ts +5 -4
- package/dist/notification/alarm-settings.d.ts +9 -3
- package/dist/notification/system-event-summary.d.ts +13 -0
- package/dist/{sleep-G4F3X9X_.js → sleep-C3gDpn7G.js} +783 -637
- package/dist/{sleep-CDCONfkt.mjs → sleep-DXKLNFvA.mjs} +783 -637
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_sleep = require("./sleep-
|
|
2
|
+
const require_sleep = require("./sleep-C3gDpn7G.js");
|
|
3
3
|
const require_event_category = require("./event-category-DmS_tLsU.js");
|
|
4
4
|
const require_composition = require("./composition-BLWAivB2.js");
|
|
5
5
|
const require_err_msg = require("./err-msg-Dx2Kor0g.js");
|
|
@@ -6008,7 +6008,16 @@ var AutomationActionSchema = zod.z.discriminatedUnion("kind", [
|
|
|
6008
6008
|
}),
|
|
6009
6009
|
zod.z.object({
|
|
6010
6010
|
kind: zod.z.literal("cap"),
|
|
6011
|
-
|
|
6011
|
+
/**
|
|
6012
|
+
* One device, several same-family devices (locks / climate family / …),
|
|
6013
|
+
* or `{ $var }` for the device that triggered the run. An array is
|
|
6014
|
+
* fan-out at codegen — each id gets the same cap.method call.
|
|
6015
|
+
*/
|
|
6016
|
+
deviceId: zod.z.union([
|
|
6017
|
+
zod.z.number().int(),
|
|
6018
|
+
zod.z.array(zod.z.number().int()).min(1),
|
|
6019
|
+
zod.z.object({ $var: zod.z.string().min(1) })
|
|
6020
|
+
]),
|
|
6012
6021
|
cap: zod.z.string().min(1),
|
|
6013
6022
|
method: zod.z.string().min(1),
|
|
6014
6023
|
/** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
|
|
@@ -6171,7 +6180,14 @@ function emitTrigger(trigger, index) {
|
|
|
6171
6180
|
function emitAction(action, index) {
|
|
6172
6181
|
switch (action.kind) {
|
|
6173
6182
|
case "wait": return ` case ${index}: await sleep(${j(action.seconds * 1e3)}); break`;
|
|
6174
|
-
case "cap":
|
|
6183
|
+
case "cap":
|
|
6184
|
+
if (Array.isArray(action.deviceId)) return ` case ${index}: {
|
|
6185
|
+
for (const deviceId of ${j(action.deviceId)}) {
|
|
6186
|
+
await actuate(deviceId, ${j(action.cap)}, ${j(action.method)}, ${j(action.args ?? {})}, vars)
|
|
6187
|
+
}
|
|
6188
|
+
break
|
|
6189
|
+
}`;
|
|
6190
|
+
return ` case ${index}: {
|
|
6175
6191
|
const deviceId = ${typeof action.deviceId === "number" ? j(action.deviceId) : `resolveTarget(vars, ${j(action.deviceId.$var)})`}
|
|
6176
6192
|
await actuate(deviceId, ${j(action.cap)}, ${j(action.method)}, ${j(action.args ?? {})}, vars)
|
|
6177
6193
|
break
|
|
@@ -6405,11 +6421,13 @@ export default function block(ctx: AddonContext) {
|
|
|
6405
6421
|
): Promise<void> {
|
|
6406
6422
|
const resolved: Record<string, unknown> = {}
|
|
6407
6423
|
for (const [k, v] of Object.entries(args)) resolved[k] = substitute(v, vars)
|
|
6424
|
+
// Forked-addon ctx.api namespaces are tRPC Proxies over a noop function
|
|
6425
|
+
// (typeof === 'function'), not plain objects — reject only null/undefined.
|
|
6408
6426
|
const client: unknown = Reflect.get(ctx.api, capToRouterKey(cap))
|
|
6409
6427
|
const proc: unknown =
|
|
6410
|
-
|
|
6428
|
+
client !== null && client !== undefined ? Reflect.get(client as object, method) : undefined
|
|
6411
6429
|
const mutate: unknown =
|
|
6412
|
-
|
|
6430
|
+
proc !== null && proc !== undefined ? Reflect.get(proc as object, 'mutate') : undefined
|
|
6413
6431
|
if (typeof mutate !== 'function') {
|
|
6414
6432
|
throw new Error('no such device method: ' + cap + '.' + method)
|
|
6415
6433
|
}
|
|
@@ -12441,7 +12459,7 @@ var detectionPipelineCapability = {
|
|
|
12441
12459
|
* This matters here more than anywhere else in the repo, because every provider
|
|
12442
12460
|
* that knows a device's host knows its PASSWORD too: `{ host, port, username,
|
|
12443
12461
|
* password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
|
|
12444
|
-
* and `http://admin:hunter2@192.168.
|
|
12462
|
+
* and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
|
|
12445
12463
|
* camera's own page will ask for its own login. That is correct, and pre-
|
|
12446
12464
|
* filling it is the operator's business, not ours.
|
|
12447
12465
|
*
|
|
@@ -17904,6 +17922,17 @@ var SendResultSchema = zod.z.object({
|
|
|
17904
17922
|
});
|
|
17905
17923
|
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
17906
17924
|
var TestResultSchema = SendResultSchema;
|
|
17925
|
+
/**
|
|
17926
|
+
* Pre-save credential probe against a partial (unsaved) target config.
|
|
17927
|
+
* `resolvedUrl` never includes secrets (token stripped from path).
|
|
17928
|
+
*/
|
|
17929
|
+
var ProbeTargetConfigResultSchema = zod.z.object({
|
|
17930
|
+
ok: zod.z.boolean(),
|
|
17931
|
+
resolvedUrl: zod.z.string(),
|
|
17932
|
+
httpStatus: zod.z.number().int().optional(),
|
|
17933
|
+
stateInstance: zod.z.string().optional(),
|
|
17934
|
+
error: zod.z.string().optional()
|
|
17935
|
+
});
|
|
17907
17936
|
var notificationOutputCapability = {
|
|
17908
17937
|
name: "notification-output",
|
|
17909
17938
|
scope: "system",
|
|
@@ -17911,10 +17940,32 @@ var notificationOutputCapability = {
|
|
|
17911
17940
|
methods: {
|
|
17912
17941
|
listTargetKinds: require_sleep.method(zod.z.object({}), zod.z.array(TargetKindSchema)),
|
|
17913
17942
|
listTargets: require_sleep.method(zod.z.object({}), zod.z.array(TargetSchema), { auth: "admin" }),
|
|
17943
|
+
/**
|
|
17944
|
+
* One target WITH secrets — admin edit / duplicate hydration only.
|
|
17945
|
+
* `listTargets` stays redacted; the editor loads this so password fields
|
|
17946
|
+
* are filled (masked in the input) and a save can round-trip the token
|
|
17947
|
+
* when a destination changes (Duplicate with a new chatId, etc.).
|
|
17948
|
+
*/
|
|
17949
|
+
getTarget: require_sleep.method(zod.z.object({ targetId: zod.z.string() }), TargetSchema, { auth: "admin" }),
|
|
17914
17950
|
discoverTargets: require_sleep.method(zod.z.object({
|
|
17915
17951
|
kind: zod.z.string(),
|
|
17916
|
-
config: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
|
|
17952
|
+
config: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
|
|
17953
|
+
/**
|
|
17954
|
+
* When editing / duplicating, the blank password field never round-trips
|
|
17955
|
+
* the stored token. Pass the source target id so the provider can restore
|
|
17956
|
+
* secrets server-side before dialling (same merge as upsert).
|
|
17957
|
+
*/
|
|
17958
|
+
targetId: zod.z.string().optional()
|
|
17917
17959
|
}), zod.z.array(DiscoveredTargetSchema), { auth: "admin" }),
|
|
17960
|
+
probeTargetConfig: require_sleep.method(zod.z.object({
|
|
17961
|
+
kind: zod.z.string(),
|
|
17962
|
+
config: zod.z.record(zod.z.string(), zod.z.unknown()),
|
|
17963
|
+
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
17964
|
+
targetId: zod.z.string().optional()
|
|
17965
|
+
}), ProbeTargetConfigResultSchema, {
|
|
17966
|
+
kind: "mutation",
|
|
17967
|
+
auth: "admin"
|
|
17968
|
+
}),
|
|
17918
17969
|
send: require_sleep.method(zod.z.object({
|
|
17919
17970
|
targetId: zod.z.string(),
|
|
17920
17971
|
notification: NotificationSchema
|
|
@@ -17929,7 +17980,16 @@ var notificationOutputCapability = {
|
|
|
17929
17980
|
kind: "mutation",
|
|
17930
17981
|
auth: "admin"
|
|
17931
17982
|
}),
|
|
17932
|
-
upsertTarget: require_sleep.method(zod.z.object({
|
|
17983
|
+
upsertTarget: require_sleep.method(zod.z.object({
|
|
17984
|
+
target: TargetSchema,
|
|
17985
|
+
/**
|
|
17986
|
+
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
17987
|
+
* existing row. The UI never holds the stored token; blank / redacted
|
|
17988
|
+
* password fields are restored from this source (D634 still applies if
|
|
17989
|
+
* destinations diverge without a re-typed secret).
|
|
17990
|
+
*/
|
|
17991
|
+
cloneSecretsFrom: zod.z.string().optional()
|
|
17992
|
+
}), TargetSchema, {
|
|
17933
17993
|
kind: "mutation",
|
|
17934
17994
|
auth: "admin"
|
|
17935
17995
|
}),
|
|
@@ -21462,12 +21522,33 @@ var NC_ALARM_NONBLOCKING_MAX = 200;
|
|
|
21462
21522
|
var NcAlarmDelaySecSchema = zod.z.number().int().min(0).max(600);
|
|
21463
21523
|
var NcAlarmTriggeredSecSchema = zod.z.number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
|
|
21464
21524
|
var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
|
|
21525
|
+
/**
|
|
21526
|
+
* What the panel does when a bounded triggered window ends.
|
|
21527
|
+
* - `rearmAfter` — return to the armed mode
|
|
21528
|
+
* - `disableAfter` — auto-disarm
|
|
21529
|
+
* - `doNothing` — stay triggered until a human disarms
|
|
21530
|
+
*/
|
|
21531
|
+
var NcAlarmPostTriggeredActionSchema = zod.z.enum([
|
|
21532
|
+
"rearmAfter",
|
|
21533
|
+
"disableAfter",
|
|
21534
|
+
"doNothing"
|
|
21535
|
+
]);
|
|
21465
21536
|
/** One mode's OVERRIDES. An absent field inherits the global value (D697). */
|
|
21466
21537
|
var NcAlarmModeDelaysSchema = zod.z.object({
|
|
21467
21538
|
mode: AlarmArmModeSchema,
|
|
21468
21539
|
exitDelaySec: NcAlarmDelaySecSchema.optional(),
|
|
21469
21540
|
entryDelaySec: NcAlarmDelaySecSchema.optional(),
|
|
21470
|
-
|
|
21541
|
+
/**
|
|
21542
|
+
* Duration of `triggered` before {@link postTriggeredAction}. Kept as the
|
|
21543
|
+
* historical field name so older clients still read/write a number.
|
|
21544
|
+
*/
|
|
21545
|
+
triggeredDurationSec: NcAlarmTriggeredSecSchema.optional(),
|
|
21546
|
+
postTriggeredAction: NcAlarmPostTriggeredActionSchema.optional(),
|
|
21547
|
+
/**
|
|
21548
|
+
* When this mode may be armed. Absent / null = always allowed (same as a
|
|
21549
|
+
* rule with no `schedule`). Evaluated with {@link isScheduleActive}.
|
|
21550
|
+
*/
|
|
21551
|
+
schedule: NcScheduleSchema.optional()
|
|
21471
21552
|
});
|
|
21472
21553
|
var NcAlarmModeDelaysListSchema = zod.z.array(NcAlarmModeDelaysSchema).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
|
|
21473
21554
|
/**
|
|
@@ -21479,7 +21560,10 @@ var NcAlarmModeDelaysEditSchema = zod.z.object({
|
|
|
21479
21560
|
mode: AlarmArmModeSchema,
|
|
21480
21561
|
exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
|
|
21481
21562
|
entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
|
|
21482
|
-
triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
|
|
21563
|
+
triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
|
|
21564
|
+
postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
|
|
21565
|
+
/** Set a schedule, or `null` to clear (mode always allowed again). */
|
|
21566
|
+
schedule: NcScheduleSchema.nullable().optional()
|
|
21483
21567
|
});
|
|
21484
21568
|
var NcAlarmModeDelaysEditListSchema = zod.z.array(NcAlarmModeDelaysEditSchema).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
|
|
21485
21569
|
/** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
|
|
@@ -21552,12 +21636,18 @@ var NcAlarmSettingsSchema = zod.z.object({
|
|
|
21552
21636
|
/** Grace period between a trigger and the alarm firing. 0 = immediate. */
|
|
21553
21637
|
entryDelaySec: NcAlarmDelaySecSchema,
|
|
21554
21638
|
/**
|
|
21555
|
-
* How long `triggered` lasts before
|
|
21556
|
-
*
|
|
21557
|
-
*
|
|
21639
|
+
* How long `triggered` lasts before {@link postTriggeredAction} runs.
|
|
21640
|
+
* Ignored when the action is `doNothing`. Historical name kept so older
|
|
21641
|
+
* clients still round-trip a number.
|
|
21558
21642
|
*/
|
|
21559
21643
|
triggeredDurationSec: NcAlarmTriggeredSecSchema,
|
|
21560
21644
|
/**
|
|
21645
|
+
* What happens when the triggered window ends. Absent on a blob older than
|
|
21646
|
+
* this field → derived from {@link triggeredDurationSec} (`>0` ⇒ rearmAfter,
|
|
21647
|
+
* else doNothing).
|
|
21648
|
+
*/
|
|
21649
|
+
postTriggeredAction: NcAlarmPostTriggeredActionSchema.optional(),
|
|
21650
|
+
/**
|
|
21561
21651
|
* Deprecated by D630 — every transition is announced. Parsed, never read;
|
|
21562
21652
|
* remove after one release. Optional so an older admin's patch (which still
|
|
21563
21653
|
* sends it) parses rather than failing the whole save.
|
|
@@ -37008,7 +37098,7 @@ var LocalInterfaceSchema = zod.z.object({
|
|
|
37008
37098
|
name: zod.z.string(),
|
|
37009
37099
|
family: zod.z.enum(["IPv4", "IPv6"]),
|
|
37010
37100
|
address: zod.z.string(),
|
|
37011
|
-
/** CIDR shorthand (e.g. `192.168.
|
|
37101
|
+
/** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
|
|
37012
37102
|
cidr: zod.z.string(),
|
|
37013
37103
|
/** OS netmask. Stable across calls so the SDK can hash on it. */
|
|
37014
37104
|
netmask: zod.z.string(),
|
|
@@ -37207,7 +37297,7 @@ var localNetworkCapability = {
|
|
|
37207
37297
|
* every client a second authority on a socket only the hub binds. A viewer
|
|
37208
37298
|
* configured with a port-less public URL (`https://camstack.example.top`)
|
|
37209
37299
|
* infers 443 from the scheme, asks with 443, and was handed
|
|
37210
|
-
* `https://192.168.
|
|
37300
|
+
* `https://192.168.x.x:443` for a hub listening on 4443. That candidate
|
|
37211
37301
|
* cannot ever answer, and losing its race reads in the log exactly like
|
|
37212
37302
|
* "the LAN was tried and it was slower" — so an operator sitting on his own
|
|
37213
37303
|
* WiFi stayed on the public tunnel for weeks, with the LAN candidate born
|
|
@@ -37666,7 +37756,7 @@ var MeshPeerSchema = zod.z.object({
|
|
|
37666
37756
|
tags: zod.z.array(zod.z.string()).readonly(),
|
|
37667
37757
|
/** True when the peer advertises itself as an exit-node candidate. */
|
|
37668
37758
|
exitNodeOption: zod.z.boolean(),
|
|
37669
|
-
/** Subnet routes the peer advertises (e.g. `["192.168.
|
|
37759
|
+
/** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
|
|
37670
37760
|
advertisedRoutes: zod.z.array(zod.z.string()).readonly(),
|
|
37671
37761
|
/** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
|
|
37672
37762
|
userLogin: zod.z.string().nullable(),
|
|
@@ -47089,7 +47179,8 @@ function roomCompositionExample(input) {
|
|
|
47089
47179
|
return require_composition.CompositionSchema.parse({
|
|
47090
47180
|
target: {
|
|
47091
47181
|
kind: "new",
|
|
47092
|
-
type: require_err_msg.DeviceType.Sensor
|
|
47182
|
+
type: require_err_msg.DeviceType.Sensor,
|
|
47183
|
+
role: require_err_msg.DeviceRole.TemperatureSensor
|
|
47093
47184
|
},
|
|
47094
47185
|
features: [{
|
|
47095
47186
|
kind: "fields",
|
|
@@ -53511,6 +53602,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
53511
53602
|
addonId: null,
|
|
53512
53603
|
access: "view"
|
|
53513
53604
|
},
|
|
53605
|
+
"notificationOutput.getTarget": {
|
|
53606
|
+
capName: "notification-output",
|
|
53607
|
+
capScope: "system",
|
|
53608
|
+
addonId: null,
|
|
53609
|
+
access: "view"
|
|
53610
|
+
},
|
|
53514
53611
|
"notificationOutput.listTargetKinds": {
|
|
53515
53612
|
capName: "notification-output",
|
|
53516
53613
|
capScope: "system",
|
|
@@ -53523,6 +53620,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
53523
53620
|
addonId: null,
|
|
53524
53621
|
access: "view"
|
|
53525
53622
|
},
|
|
53623
|
+
"notificationOutput.probeTargetConfig": {
|
|
53624
|
+
capName: "notification-output",
|
|
53625
|
+
capScope: "system",
|
|
53626
|
+
addonId: null,
|
|
53627
|
+
access: "create"
|
|
53628
|
+
},
|
|
53526
53629
|
"notificationOutput.send": {
|
|
53527
53630
|
capName: "notification-output",
|
|
53528
53631
|
capScope: "system",
|
|
@@ -57645,6 +57748,62 @@ var DEVICE_DO_ACTIONS = [
|
|
|
57645
57748
|
method: "stop",
|
|
57646
57749
|
args: {}
|
|
57647
57750
|
},
|
|
57751
|
+
{
|
|
57752
|
+
id: "valve.open",
|
|
57753
|
+
label: "Open valve",
|
|
57754
|
+
cap: "valve",
|
|
57755
|
+
method: "open",
|
|
57756
|
+
args: {}
|
|
57757
|
+
},
|
|
57758
|
+
{
|
|
57759
|
+
id: "valve.close",
|
|
57760
|
+
label: "Close valve",
|
|
57761
|
+
cap: "valve",
|
|
57762
|
+
method: "close",
|
|
57763
|
+
args: {}
|
|
57764
|
+
},
|
|
57765
|
+
{
|
|
57766
|
+
id: "valve.stop",
|
|
57767
|
+
label: "Stop valve",
|
|
57768
|
+
cap: "valve",
|
|
57769
|
+
method: "stop",
|
|
57770
|
+
args: {}
|
|
57771
|
+
},
|
|
57772
|
+
{
|
|
57773
|
+
id: "humidifier.on",
|
|
57774
|
+
label: "Humidifier on",
|
|
57775
|
+
cap: "humidifier",
|
|
57776
|
+
method: "setOn",
|
|
57777
|
+
args: { on: true }
|
|
57778
|
+
},
|
|
57779
|
+
{
|
|
57780
|
+
id: "humidifier.off",
|
|
57781
|
+
label: "Humidifier off",
|
|
57782
|
+
cap: "humidifier",
|
|
57783
|
+
method: "setOn",
|
|
57784
|
+
args: { on: false }
|
|
57785
|
+
},
|
|
57786
|
+
{
|
|
57787
|
+
id: "waterHeater.off",
|
|
57788
|
+
label: "Water heater off",
|
|
57789
|
+
cap: "water-heater",
|
|
57790
|
+
method: "setOperationMode",
|
|
57791
|
+
args: { mode: "off" }
|
|
57792
|
+
},
|
|
57793
|
+
{
|
|
57794
|
+
id: "waterHeater.awayOn",
|
|
57795
|
+
label: "Water heater away on",
|
|
57796
|
+
cap: "water-heater",
|
|
57797
|
+
method: "setAway",
|
|
57798
|
+
args: { on: true }
|
|
57799
|
+
},
|
|
57800
|
+
{
|
|
57801
|
+
id: "waterHeater.awayOff",
|
|
57802
|
+
label: "Water heater away off",
|
|
57803
|
+
cap: "water-heater",
|
|
57804
|
+
method: "setAway",
|
|
57805
|
+
args: { on: false }
|
|
57806
|
+
},
|
|
57648
57807
|
{
|
|
57649
57808
|
id: "climate.off",
|
|
57650
57809
|
label: "Climate off",
|
|
@@ -57715,6 +57874,115 @@ var DEVICE_DO_ACTIONS = [
|
|
|
57715
57874
|
method: "returnToBase",
|
|
57716
57875
|
args: {}
|
|
57717
57876
|
},
|
|
57877
|
+
{
|
|
57878
|
+
id: "lawnMower.start",
|
|
57879
|
+
label: "Start mowing",
|
|
57880
|
+
cap: "lawn-mower-control",
|
|
57881
|
+
method: "startMowing",
|
|
57882
|
+
args: {}
|
|
57883
|
+
},
|
|
57884
|
+
{
|
|
57885
|
+
id: "lawnMower.pause",
|
|
57886
|
+
label: "Pause mower",
|
|
57887
|
+
cap: "lawn-mower-control",
|
|
57888
|
+
method: "pause",
|
|
57889
|
+
args: {}
|
|
57890
|
+
},
|
|
57891
|
+
{
|
|
57892
|
+
id: "lawnMower.dock",
|
|
57893
|
+
label: "Dock mower",
|
|
57894
|
+
cap: "lawn-mower-control",
|
|
57895
|
+
method: "dock",
|
|
57896
|
+
args: {}
|
|
57897
|
+
},
|
|
57898
|
+
{
|
|
57899
|
+
id: "media.play",
|
|
57900
|
+
label: "Play",
|
|
57901
|
+
cap: "media-player",
|
|
57902
|
+
method: "play",
|
|
57903
|
+
args: {}
|
|
57904
|
+
},
|
|
57905
|
+
{
|
|
57906
|
+
id: "media.pause",
|
|
57907
|
+
label: "Pause media",
|
|
57908
|
+
cap: "media-player",
|
|
57909
|
+
method: "pause",
|
|
57910
|
+
args: {}
|
|
57911
|
+
},
|
|
57912
|
+
{
|
|
57913
|
+
id: "media.stop",
|
|
57914
|
+
label: "Stop media",
|
|
57915
|
+
cap: "media-player",
|
|
57916
|
+
method: "stop",
|
|
57917
|
+
args: {}
|
|
57918
|
+
},
|
|
57919
|
+
{
|
|
57920
|
+
id: "media.next",
|
|
57921
|
+
label: "Next track",
|
|
57922
|
+
cap: "media-player",
|
|
57923
|
+
method: "next",
|
|
57924
|
+
args: {}
|
|
57925
|
+
},
|
|
57926
|
+
{
|
|
57927
|
+
id: "media.previous",
|
|
57928
|
+
label: "Previous track",
|
|
57929
|
+
cap: "media-player",
|
|
57930
|
+
method: "previous",
|
|
57931
|
+
args: {}
|
|
57932
|
+
},
|
|
57933
|
+
{
|
|
57934
|
+
id: "script.run",
|
|
57935
|
+
label: "Run script",
|
|
57936
|
+
cap: "script-runner",
|
|
57937
|
+
method: "run",
|
|
57938
|
+
args: {}
|
|
57939
|
+
},
|
|
57940
|
+
{
|
|
57941
|
+
id: "script.stop",
|
|
57942
|
+
label: "Stop script",
|
|
57943
|
+
cap: "script-runner",
|
|
57944
|
+
method: "stop",
|
|
57945
|
+
args: {}
|
|
57946
|
+
},
|
|
57947
|
+
{
|
|
57948
|
+
id: "haAutomation.enable",
|
|
57949
|
+
label: "Enable automation",
|
|
57950
|
+
cap: "automation-control",
|
|
57951
|
+
method: "enable",
|
|
57952
|
+
args: {}
|
|
57953
|
+
},
|
|
57954
|
+
{
|
|
57955
|
+
id: "haAutomation.disable",
|
|
57956
|
+
label: "Disable automation",
|
|
57957
|
+
cap: "automation-control",
|
|
57958
|
+
method: "disable",
|
|
57959
|
+
args: {}
|
|
57960
|
+
},
|
|
57961
|
+
{
|
|
57962
|
+
id: "haAutomation.trigger",
|
|
57963
|
+
label: "Trigger automation",
|
|
57964
|
+
cap: "automation-control",
|
|
57965
|
+
method: "trigger",
|
|
57966
|
+
args: {}
|
|
57967
|
+
},
|
|
57968
|
+
{
|
|
57969
|
+
id: "petFeeder.feed",
|
|
57970
|
+
label: "Feed",
|
|
57971
|
+
cap: "pet-feeder",
|
|
57972
|
+
method: "feed",
|
|
57973
|
+
openArgs: [{
|
|
57974
|
+
key: "grams",
|
|
57975
|
+
label: "Grams",
|
|
57976
|
+
kind: "number"
|
|
57977
|
+
}]
|
|
57978
|
+
},
|
|
57979
|
+
{
|
|
57980
|
+
id: "petFeeder.callPet",
|
|
57981
|
+
label: "Call pet",
|
|
57982
|
+
cap: "pet-feeder",
|
|
57983
|
+
method: "callPet",
|
|
57984
|
+
args: {}
|
|
57985
|
+
},
|
|
57718
57986
|
{
|
|
57719
57987
|
id: "ptz.goHome",
|
|
57720
57988
|
label: "PTZ go home",
|
|
@@ -57942,6 +58210,94 @@ function bakedArgsEqual(action, args) {
|
|
|
57942
58210
|
return argsEqual(action.args, args);
|
|
57943
58211
|
}
|
|
57944
58212
|
/**
|
|
58213
|
+
* Catalogue caps a `DeviceType` is expected to offer in the Do picker.
|
|
58214
|
+
*
|
|
58215
|
+
* Exhaustive over {@link DeviceType}: adding a new enum member without an
|
|
58216
|
+
* entry fails the TypeScript build here (same pattern as
|
|
58217
|
+
* {@link DEVICE_TYPE_CONTROL_KIND}). An empty list is a deliberate choice
|
|
58218
|
+
* for read-only / non-actuatable types — never "forgotten".
|
|
58219
|
+
*
|
|
58220
|
+
* Camera accessories (ptz, privacy-mask, …) are listed on Camera even though
|
|
58221
|
+
* a given camera may bind only a subset; {@link actionsForBoundCaps} still
|
|
58222
|
+
* filters to what the device actually binds.
|
|
58223
|
+
*/
|
|
58224
|
+
var DEVICE_TYPE_DO_CAPS = {
|
|
58225
|
+
[require_err_msg.DeviceType.Camera]: [
|
|
58226
|
+
"ptz",
|
|
58227
|
+
"ptz-autotrack",
|
|
58228
|
+
"privacy-mask",
|
|
58229
|
+
"day-night",
|
|
58230
|
+
"reboot",
|
|
58231
|
+
"motion-trigger"
|
|
58232
|
+
],
|
|
58233
|
+
[require_err_msg.DeviceType.Hub]: [],
|
|
58234
|
+
[require_err_msg.DeviceType.Light]: ["switch", "brightness"],
|
|
58235
|
+
[require_err_msg.DeviceType.Siren]: ["switch", "motion-trigger"],
|
|
58236
|
+
[require_err_msg.DeviceType.Switch]: ["switch", "motion-trigger"],
|
|
58237
|
+
[require_err_msg.DeviceType.Sensor]: [],
|
|
58238
|
+
[require_err_msg.DeviceType.Thermostat]: ["climate-control"],
|
|
58239
|
+
[require_err_msg.DeviceType.Climate]: ["climate-control"],
|
|
58240
|
+
[require_err_msg.DeviceType.Button]: ["button"],
|
|
58241
|
+
[require_err_msg.DeviceType.EventEmitter]: [],
|
|
58242
|
+
[require_err_msg.DeviceType.Update]: [],
|
|
58243
|
+
[require_err_msg.DeviceType.Generic]: [],
|
|
58244
|
+
[require_err_msg.DeviceType.Notifier]: [],
|
|
58245
|
+
[require_err_msg.DeviceType.Script]: ["script-runner"],
|
|
58246
|
+
[require_err_msg.DeviceType.Automation]: ["automation-control"],
|
|
58247
|
+
[require_err_msg.DeviceType.Lock]: ["lock-control"],
|
|
58248
|
+
[require_err_msg.DeviceType.Cover]: ["cover"],
|
|
58249
|
+
[require_err_msg.DeviceType.Valve]: ["valve"],
|
|
58250
|
+
[require_err_msg.DeviceType.Humidifier]: ["humidifier"],
|
|
58251
|
+
[require_err_msg.DeviceType.WaterHeater]: ["water-heater"],
|
|
58252
|
+
[require_err_msg.DeviceType.Fan]: ["fan-control", "switch"],
|
|
58253
|
+
[require_err_msg.DeviceType.MediaPlayer]: ["media-player"],
|
|
58254
|
+
[require_err_msg.DeviceType.AlarmPanel]: ["alarm-panel"],
|
|
58255
|
+
[require_err_msg.DeviceType.Control]: [],
|
|
58256
|
+
[require_err_msg.DeviceType.Presence]: [],
|
|
58257
|
+
[require_err_msg.DeviceType.Weather]: [],
|
|
58258
|
+
[require_err_msg.DeviceType.Vacuum]: ["vacuum-control"],
|
|
58259
|
+
[require_err_msg.DeviceType.LawnMower]: ["lawn-mower-control"],
|
|
58260
|
+
[require_err_msg.DeviceType.Container]: [],
|
|
58261
|
+
[require_err_msg.DeviceType.Image]: [],
|
|
58262
|
+
[require_err_msg.DeviceType.PetFeeder]: ["pet-feeder"]
|
|
58263
|
+
};
|
|
58264
|
+
/**
|
|
58265
|
+
* Whether a device type belongs in a Do / automation action device picker.
|
|
58266
|
+
*
|
|
58267
|
+
* Containers stay in {@link DEVICE_TYPE_DO_CAPS} (empty, for exhaustiveness)
|
|
58268
|
+
* but must never appear as selectable targets — actuate the children instead.
|
|
58269
|
+
*/
|
|
58270
|
+
function isDoPickerDeviceType(type) {
|
|
58271
|
+
return type !== require_err_msg.DeviceType.Container;
|
|
58272
|
+
}
|
|
58273
|
+
/**
|
|
58274
|
+
* Do-picker family id — devices that share one may be multi-selected for
|
|
58275
|
+
* the same action (several locks, the climate family, cover+valve, …).
|
|
58276
|
+
*
|
|
58277
|
+
* Distinct from {@link DeviceControlKind}: humidifier / water-heater keep
|
|
58278
|
+
* their own control widgets but author with climate siblings.
|
|
58279
|
+
*/
|
|
58280
|
+
function deviceDoFamily(type) {
|
|
58281
|
+
switch (type) {
|
|
58282
|
+
case require_err_msg.DeviceType.Climate:
|
|
58283
|
+
case require_err_msg.DeviceType.Thermostat:
|
|
58284
|
+
case require_err_msg.DeviceType.Humidifier:
|
|
58285
|
+
case require_err_msg.DeviceType.WaterHeater: return "climate-family";
|
|
58286
|
+
case require_err_msg.DeviceType.Cover:
|
|
58287
|
+
case require_err_msg.DeviceType.Valve: return "cover-family";
|
|
58288
|
+
case require_err_msg.DeviceType.Switch:
|
|
58289
|
+
case require_err_msg.DeviceType.Siren:
|
|
58290
|
+
case require_err_msg.DeviceType.Light: return "switch-family";
|
|
58291
|
+
case require_err_msg.DeviceType.Vacuum:
|
|
58292
|
+
case require_err_msg.DeviceType.LawnMower: return "robot-family";
|
|
58293
|
+
default: return type;
|
|
58294
|
+
}
|
|
58295
|
+
}
|
|
58296
|
+
/** True when two device types may share one multi-target Do step. */
|
|
58297
|
+
function sameDoFamily(leftType, rightType) {
|
|
58298
|
+
return deviceDoFamily(leftType) === deviceDoFamily(rightType);
|
|
58299
|
+
}
|
|
58300
|
+
/**
|
|
57945
58301
|
* Actions offered for a device that binds the given caps.
|
|
57946
58302
|
*
|
|
57947
58303
|
* Only catalogue entries whose cap is bound AND still actuatable in
|
|
@@ -57952,6 +58308,50 @@ function actionsForBoundCaps(boundCaps) {
|
|
|
57952
58308
|
const set = new Set(boundCaps);
|
|
57953
58309
|
return DEVICE_DO_ACTIONS.filter((action) => set.has(action.cap) && isDoActionActuatable(action));
|
|
57954
58310
|
}
|
|
58311
|
+
/**
|
|
58312
|
+
* Catalogue actions for a wire `DeviceType` string — the fallback when
|
|
58313
|
+
* bindings have not answered yet (or answered empty for a typed actuator).
|
|
58314
|
+
* Unknown type strings → empty.
|
|
58315
|
+
*/
|
|
58316
|
+
function actionsForDeviceType(type) {
|
|
58317
|
+
if (!Object.values(require_err_msg.DeviceType).includes(type)) return [];
|
|
58318
|
+
return actionsForBoundCaps(DEVICE_TYPE_DO_CAPS[type]);
|
|
58319
|
+
}
|
|
58320
|
+
/**
|
|
58321
|
+
* Union of bound-cap actions with the type's expected catalogue caps.
|
|
58322
|
+
*
|
|
58323
|
+
* Bindings win for filtering (a lock without `lock-control` bound still
|
|
58324
|
+
* offers nothing from bindings alone); the type map fills gaps when the
|
|
58325
|
+
* binding read is empty so a Lock / Valve / Climate never shows
|
|
58326
|
+
* "No actions for this device" solely because getBindings lagged.
|
|
58327
|
+
*/
|
|
58328
|
+
function actionsForDevice(input) {
|
|
58329
|
+
const fromBound = input.boundCaps !== void 0 && input.boundCaps.length > 0 ? actionsForBoundCaps(input.boundCaps) : [];
|
|
58330
|
+
if (fromBound.length > 0) return fromBound;
|
|
58331
|
+
if (input.deviceType !== void 0 && input.deviceType.length > 0) return actionsForDeviceType(input.deviceType);
|
|
58332
|
+
return [];
|
|
58333
|
+
}
|
|
58334
|
+
/**
|
|
58335
|
+
* Intersection of {@link actionsForDevice} across several targets — what a
|
|
58336
|
+
* multi-select same-family Do step may offer.
|
|
58337
|
+
*/
|
|
58338
|
+
function actionsForDevices(targets) {
|
|
58339
|
+
if (targets.length === 0) return [];
|
|
58340
|
+
let common = null;
|
|
58341
|
+
for (const target of targets) {
|
|
58342
|
+
const offered = actionsForDevice({
|
|
58343
|
+
boundCaps: target.boundCaps,
|
|
58344
|
+
deviceType: target.deviceType
|
|
58345
|
+
});
|
|
58346
|
+
if (common === null) {
|
|
58347
|
+
common = offered;
|
|
58348
|
+
continue;
|
|
58349
|
+
}
|
|
58350
|
+
const ids = new Set(offered.map((a) => a.id));
|
|
58351
|
+
common = common.filter((a) => ids.has(a.id));
|
|
58352
|
+
}
|
|
58353
|
+
return common ?? [];
|
|
58354
|
+
}
|
|
57955
58355
|
/** The whole catalogue (still actuatable) — for a `{$var}` automation target. */
|
|
57956
58356
|
function allDoActions() {
|
|
57957
58357
|
return DEVICE_DO_ACTIONS.filter(isDoActionActuatable);
|
|
@@ -65196,7 +65596,9 @@ function createSystemProxy(api) {
|
|
|
65196
65596
|
notificationOutput: {
|
|
65197
65597
|
listTargetKinds: (input) => dispatch("notificationOutput", "listTargetKinds", "query", input),
|
|
65198
65598
|
listTargets: (input) => dispatch("notificationOutput", "listTargets", "query", input),
|
|
65599
|
+
getTarget: (input) => dispatch("notificationOutput", "getTarget", "query", input),
|
|
65199
65600
|
discoverTargets: (input) => dispatch("notificationOutput", "discoverTargets", "query", input),
|
|
65601
|
+
probeTargetConfig: (input) => dispatch("notificationOutput", "probeTargetConfig", "mutation", input),
|
|
65200
65602
|
send: (input) => dispatch("notificationOutput", "send", "mutation", input),
|
|
65201
65603
|
testTarget: (input) => dispatch("notificationOutput", "testTarget", "mutation", input),
|
|
65202
65604
|
upsertTarget: (input) => dispatch("notificationOutput", "upsertTarget", "mutation", input),
|
|
@@ -67276,6 +67678,10 @@ function bindingPullsAlarmTrigger(binding, sequenceActionsOf) {
|
|
|
67276
67678
|
if (steps === void 0) return false;
|
|
67277
67679
|
return steps.some((step) => step.kind === "cap" && step.cap === ALARM_PANEL_CAP && step.method === ALARM_PANEL_TRIGGER_METHOD);
|
|
67278
67680
|
}
|
|
67681
|
+
/** True when the rule's deviceState gate names any `armed_*` word. */
|
|
67682
|
+
function ruleGatedOnArmedState(rule) {
|
|
67683
|
+
return (rule.conditions.deviceState?.states ?? []).some((s) => s.trim().toLowerCase().startsWith(ARMED_WORD_PREFIX));
|
|
67684
|
+
}
|
|
67279
67685
|
/**
|
|
67280
67686
|
* A rule belongs to the alarm when its `deviceState` gate names ANY device's
|
|
67281
67687
|
* `armed_*` word, or an on-match binding pulls the alarm panel's trigger
|
|
@@ -67283,10 +67689,19 @@ function bindingPullsAlarmTrigger(binding, sequenceActionsOf) {
|
|
|
67283
67689
|
* escalation.
|
|
67284
67690
|
*/
|
|
67285
67691
|
function ruleBelongsToAlarm(rule) {
|
|
67286
|
-
if ((rule
|
|
67692
|
+
if (ruleGatedOnArmedState(rule)) return true;
|
|
67287
67693
|
for (const binding of rule.actions?.onTrigger ?? []) if (bindingPullsAlarmTrigger(binding, rule.sequenceActionsOf)) return true;
|
|
67288
67694
|
return false;
|
|
67289
67695
|
}
|
|
67696
|
+
/**
|
|
67697
|
+
* A rule gated on `armed_*` auto-triggers the CamStack `alarm-panel` on match
|
|
67698
|
+
* — no `onTrigger` sequence required. Sirens are never part of this path.
|
|
67699
|
+
* An explicit `alarm-panel.trigger` binding without an armed gate stays
|
|
67700
|
+
* explicit actuation only ({@link ruleBelongsToAlarm}).
|
|
67701
|
+
*/
|
|
67702
|
+
function ruleAutoTriggersAlarm(rule) {
|
|
67703
|
+
return ruleGatedOnArmedState(rule);
|
|
67704
|
+
}
|
|
67290
67705
|
function isOpeningKind(kind) {
|
|
67291
67706
|
const k = kind.trim().toLowerCase();
|
|
67292
67707
|
return NC_ALARM_OPENING_EVENT_KINDS.some((opening) => opening === k);
|
|
@@ -67352,6 +67767,14 @@ var NC_ALARM_DELAY_FIELDS = [
|
|
|
67352
67767
|
"entryDelaySec",
|
|
67353
67768
|
"triggeredDurationSec"
|
|
67354
67769
|
];
|
|
67770
|
+
/**
|
|
67771
|
+
* Derive the post-triggered action from a stored blob that may predate the field:
|
|
67772
|
+
* a positive duration meant re-arm; zero/absent meant stay triggered.
|
|
67773
|
+
*/
|
|
67774
|
+
function derivePostTriggeredAction(action, triggeredDurationSec) {
|
|
67775
|
+
if (action !== void 0) return action;
|
|
67776
|
+
return triggeredDurationSec > 0 ? "rearmAfter" : "doNothing";
|
|
67777
|
+
}
|
|
67355
67778
|
/** The mode's value when it overrides the field, else the global one. */
|
|
67356
67779
|
function pick(override, global) {
|
|
67357
67780
|
return override === void 0 ? {
|
|
@@ -67368,14 +67791,19 @@ function resolveModeDelays(settings, mode) {
|
|
|
67368
67791
|
const exit = pick(entry?.exitDelaySec, settings.exitDelaySec);
|
|
67369
67792
|
const entryDelay = pick(entry?.entryDelaySec, settings.entryDelaySec);
|
|
67370
67793
|
const triggered = pick(entry?.triggeredDurationSec, settings.triggeredDurationSec);
|
|
67794
|
+
const actionOverride = entry?.postTriggeredAction;
|
|
67795
|
+
const actionSource = actionOverride !== void 0 ? "mode" : "default";
|
|
67796
|
+
const postTriggeredAction = derivePostTriggeredAction(actionOverride ?? settings.postTriggeredAction, triggered.value);
|
|
67371
67797
|
return {
|
|
67372
67798
|
exitDelaySec: exit.value,
|
|
67373
67799
|
entryDelaySec: entryDelay.value,
|
|
67374
67800
|
triggeredDurationSec: triggered.value,
|
|
67801
|
+
postTriggeredAction,
|
|
67375
67802
|
source: {
|
|
67376
67803
|
exitDelaySec: exit.source,
|
|
67377
67804
|
entryDelaySec: entryDelay.source,
|
|
67378
|
-
triggeredDurationSec: triggered.source
|
|
67805
|
+
triggeredDurationSec: triggered.source,
|
|
67806
|
+
postTriggeredAction: actionSource
|
|
67379
67807
|
}
|
|
67380
67808
|
};
|
|
67381
67809
|
}
|
|
@@ -67384,6 +67812,29 @@ function edited(current, edit) {
|
|
|
67384
67812
|
if (edit === void 0) return current;
|
|
67385
67813
|
return edit === null ? void 0 : edit;
|
|
67386
67814
|
}
|
|
67815
|
+
function editedAction(current, edit) {
|
|
67816
|
+
if (edit === void 0) return current;
|
|
67817
|
+
return edit === null ? void 0 : edit;
|
|
67818
|
+
}
|
|
67819
|
+
function editedSchedule(current, edit) {
|
|
67820
|
+
if (edit === void 0) return current;
|
|
67821
|
+
return edit === null ? void 0 : edit;
|
|
67822
|
+
}
|
|
67823
|
+
function sameSchedule(a, b) {
|
|
67824
|
+
if (a === void 0 && b === void 0) return true;
|
|
67825
|
+
if (a === void 0 || b === void 0) return false;
|
|
67826
|
+
if (a.invert !== b.invert || a.timezone !== b.timezone) return false;
|
|
67827
|
+
if (a.windows.length !== b.windows.length) return false;
|
|
67828
|
+
for (let i = 0; i < a.windows.length; i++) {
|
|
67829
|
+
const wa = a.windows[i];
|
|
67830
|
+
const wb = b.windows[i];
|
|
67831
|
+
if (wa === void 0 || wb === void 0) return false;
|
|
67832
|
+
if (wa.startMinute !== wb.startMinute || wa.endMinute !== wb.endMinute) return false;
|
|
67833
|
+
if (wa.days.length !== wb.days.length) return false;
|
|
67834
|
+
for (let d = 0; d < wa.days.length; d++) if (wa.days[d] !== wb.days[d]) return false;
|
|
67835
|
+
}
|
|
67836
|
+
return true;
|
|
67837
|
+
}
|
|
67387
67838
|
/**
|
|
67388
67839
|
* Apply per-field edits to the stored overrides. Returns new arrays, never mutates the input;
|
|
67389
67840
|
* an entry with no field left is dropped (the mode inherits everything again).
|
|
@@ -67397,13 +67848,17 @@ function applyModeDelaysEdits(current, edits) {
|
|
|
67397
67848
|
const exit = edited(base.exitDelaySec, edit.exitDelaySec);
|
|
67398
67849
|
const entry = edited(base.entryDelaySec, edit.entryDelaySec);
|
|
67399
67850
|
const triggered = edited(base.triggeredDurationSec, edit.triggeredDurationSec);
|
|
67851
|
+
const action = editedAction(base.postTriggeredAction, edit.postTriggeredAction);
|
|
67852
|
+
const schedule = editedSchedule(base.schedule, edit.schedule);
|
|
67400
67853
|
if (exit !== void 0) next.exitDelaySec = exit;
|
|
67401
67854
|
if (entry !== void 0) next.entryDelaySec = entry;
|
|
67402
67855
|
if (triggered !== void 0) next.triggeredDurationSec = triggered;
|
|
67856
|
+
if (action !== void 0) next.postTriggeredAction = action;
|
|
67857
|
+
if (schedule !== void 0) next.schedule = schedule;
|
|
67403
67858
|
if (at >= 0) out[at] = next;
|
|
67404
67859
|
else out.push(next);
|
|
67405
67860
|
}
|
|
67406
|
-
return out.filter((e) => e.exitDelaySec !== void 0 || e.entryDelaySec !== void 0 || e.triggeredDurationSec !== void 0);
|
|
67861
|
+
return out.filter((e) => e.exitDelaySec !== void 0 || e.entryDelaySec !== void 0 || e.triggeredDurationSec !== void 0 || e.postTriggeredAction !== void 0 || e.schedule !== void 0);
|
|
67407
67862
|
}
|
|
67408
67863
|
/**
|
|
67409
67864
|
* Put ONE device on, or take it off, ONE mode's device-id list. A no-op answers
|
|
@@ -67531,6 +67986,7 @@ function alarmPatchLanded(patch, returned) {
|
|
|
67531
67986
|
if (patch.exitDelaySec !== void 0 && patch.exitDelaySec !== returned.exitDelaySec) return false;
|
|
67532
67987
|
if (patch.entryDelaySec !== void 0 && patch.entryDelaySec !== returned.entryDelaySec) return false;
|
|
67533
67988
|
if (patch.triggeredDurationSec !== void 0 && patch.triggeredDurationSec !== returned.triggeredDurationSec) return false;
|
|
67989
|
+
if (patch.postTriggeredAction !== void 0 && patch.postTriggeredAction !== derivePostTriggeredAction(returned.postTriggeredAction, returned.triggeredDurationSec)) return false;
|
|
67534
67990
|
if (patch.announceTargets !== void 0 && !sameSet(patch.announceTargets, returned.announceTargets)) return false;
|
|
67535
67991
|
if (patch.nonBlocking !== void 0 && !sameLists(patch.nonBlocking, returned.nonBlocking ?? [])) return false;
|
|
67536
67992
|
if (patch.blocking !== void 0 && !sameLists(patch.blocking, returned.blocking ?? [])) return false;
|
|
@@ -67543,6 +67999,14 @@ function alarmPatchLanded(patch, returned) {
|
|
|
67543
67999
|
const got = fieldOf(entry, field);
|
|
67544
68000
|
if (want === null ? got !== void 0 : got !== want) return false;
|
|
67545
68001
|
}
|
|
68002
|
+
if (edit.postTriggeredAction !== void 0) {
|
|
68003
|
+
const got = entry?.postTriggeredAction;
|
|
68004
|
+
if (edit.postTriggeredAction === null ? got !== void 0 : got !== edit.postTriggeredAction) return false;
|
|
68005
|
+
}
|
|
68006
|
+
if (edit.schedule !== void 0) {
|
|
68007
|
+
const got = entry?.schedule;
|
|
68008
|
+
if (edit.schedule === null ? got !== void 0 : !sameSchedule(got, edit.schedule)) return false;
|
|
68009
|
+
}
|
|
67546
68010
|
}
|
|
67547
68011
|
if (patch.nonBlockingEdit !== void 0) {
|
|
67548
68012
|
const e = patch.nonBlockingEdit;
|
|
@@ -67563,11 +68027,12 @@ function alarmPatchLanded(patch, returned) {
|
|
|
67563
68027
|
/** Stable id of the always-present Default profile (migrated from flat settings). */
|
|
67564
68028
|
var NC_ALARM_DEFAULT_PROFILE_ID = "default";
|
|
67565
68029
|
var NC_ALARM_DEFAULT_PROFILE_NAME = "Default";
|
|
67566
|
-
/** Stock delays —
|
|
68030
|
+
/** Stock delays — re-arm 10 s after trigger (inherited by every mode). */
|
|
67567
68031
|
var NC_ALARM_SYSTEM_DEFAULT_DELAYS = {
|
|
67568
68032
|
exitDelaySec: 30,
|
|
67569
68033
|
entryDelaySec: 20,
|
|
67570
|
-
triggeredDurationSec:
|
|
68034
|
+
triggeredDurationSec: 10,
|
|
68035
|
+
postTriggeredAction: "rearmAfter"
|
|
67571
68036
|
};
|
|
67572
68037
|
/** Empty memberships + stock delays + no announce targets. */
|
|
67573
68038
|
function ncAlarmSystemDefaultSettings() {
|
|
@@ -67589,6 +68054,7 @@ function cloneAlarmSettings(settings) {
|
|
|
67589
68054
|
exitDelaySec: settings.exitDelaySec,
|
|
67590
68055
|
entryDelaySec: settings.entryDelaySec,
|
|
67591
68056
|
triggeredDurationSec: settings.triggeredDurationSec,
|
|
68057
|
+
...settings.postTriggeredAction !== void 0 ? { postTriggeredAction: settings.postTriggeredAction } : {},
|
|
67592
68058
|
...settings.announceArm !== void 0 ? { announceArm: settings.announceArm } : {},
|
|
67593
68059
|
announceTargets: [...settings.announceTargets],
|
|
67594
68060
|
nonBlocking: settings.nonBlocking.map((l) => ({
|
|
@@ -67603,7 +68069,22 @@ function cloneAlarmSettings(settings) {
|
|
|
67603
68069
|
mode: l.mode,
|
|
67604
68070
|
deviceIds: [...l.deviceIds]
|
|
67605
68071
|
})),
|
|
67606
|
-
modeDelays: settings.modeDelays.map((e) => ({
|
|
68072
|
+
modeDelays: settings.modeDelays.map((e) => ({
|
|
68073
|
+
mode: e.mode,
|
|
68074
|
+
...e.exitDelaySec !== void 0 ? { exitDelaySec: e.exitDelaySec } : {},
|
|
68075
|
+
...e.entryDelaySec !== void 0 ? { entryDelaySec: e.entryDelaySec } : {},
|
|
68076
|
+
...e.triggeredDurationSec !== void 0 ? { triggeredDurationSec: e.triggeredDurationSec } : {},
|
|
68077
|
+
...e.postTriggeredAction !== void 0 ? { postTriggeredAction: e.postTriggeredAction } : {},
|
|
68078
|
+
...e.schedule !== void 0 ? { schedule: {
|
|
68079
|
+
windows: e.schedule.windows.map((w) => ({
|
|
68080
|
+
days: [...w.days],
|
|
68081
|
+
startMinute: w.startMinute,
|
|
68082
|
+
endMinute: w.endMinute
|
|
68083
|
+
})),
|
|
68084
|
+
...e.schedule.timezone !== void 0 ? { timezone: e.schedule.timezone } : {},
|
|
68085
|
+
...e.schedule.invert === true ? { invert: true } : {}
|
|
68086
|
+
} } : {}
|
|
68087
|
+
}))
|
|
67607
68088
|
};
|
|
67608
68089
|
}
|
|
67609
68090
|
/**
|
|
@@ -68930,6 +69411,34 @@ function sendTimesOfSchedule(schedule) {
|
|
|
68930
69411
|
}
|
|
68931
69412
|
return times;
|
|
68932
69413
|
}
|
|
69414
|
+
/**
|
|
69415
|
+
* Punctual times for a `mode: 'times'` editor.
|
|
69416
|
+
*
|
|
69417
|
+
* Exact one-minute windows win. Otherwise each window's END is the fire time
|
|
69418
|
+
* (summary delivery fires when a window closes) — so a legacy 17:00→18:00 band
|
|
69419
|
+
* authored as a range still opens as a single "At 18:00" row instead of two
|
|
69420
|
+
* clocks. `null` only when inverted (cannot map to punctual rows).
|
|
69421
|
+
*/
|
|
69422
|
+
function sendTimesForEditor(schedule) {
|
|
69423
|
+
const exact = sendTimesOfSchedule(schedule);
|
|
69424
|
+
if (exact !== null) return {
|
|
69425
|
+
times: exact,
|
|
69426
|
+
approximated: false
|
|
69427
|
+
};
|
|
69428
|
+
if (schedule.invert === true) return null;
|
|
69429
|
+
const times = [];
|
|
69430
|
+
for (const window of schedule.windows) {
|
|
69431
|
+
const days = window.endMinute === 0 ? window.days.map((day) => (day + 1) % 7) : window.days;
|
|
69432
|
+
times.push({
|
|
69433
|
+
days: days.toSorted((a, b) => a - b),
|
|
69434
|
+
minute: window.endMinute
|
|
69435
|
+
});
|
|
69436
|
+
}
|
|
69437
|
+
return {
|
|
69438
|
+
times,
|
|
69439
|
+
approximated: times.length > 0
|
|
69440
|
+
};
|
|
69441
|
+
}
|
|
68933
69442
|
var SUMMARY_CONTENT_VAR = /\{\{\s*summary(?:Text|Devices|Streams|Battery|Consumables|Tanks|Detection|Nodes|Addons|Updates)\s*\}\}/;
|
|
68934
69443
|
/**
|
|
68935
69444
|
* Does a custom BODY carry the summary's content (`{{summaryText}}` or a
|
|
@@ -72400,6 +72909,7 @@ exports.DEVICE_SETTINGS_CONTRIBUTION_METHODS = require_sleep.DEVICE_SETTINGS_CON
|
|
|
72400
72909
|
exports.DEVICE_STATE_READERS = DEVICE_STATE_READERS;
|
|
72401
72910
|
exports.DEVICE_STATUS_METHOD = require_sleep.DEVICE_STATUS_METHOD;
|
|
72402
72911
|
exports.DEVICE_TYPE_CONTROL_KIND = DEVICE_TYPE_CONTROL_KIND;
|
|
72912
|
+
exports.DEVICE_TYPE_DO_CAPS = DEVICE_TYPE_DO_CAPS;
|
|
72403
72913
|
exports.DEVICE_TYPE_INFO = DEVICE_TYPE_INFO;
|
|
72404
72914
|
exports.DISPLAY_ICON_GROUPS = DISPLAY_ICON_GROUPS;
|
|
72405
72915
|
exports.DISPLAY_ICON_KEYS = DISPLAY_ICON_KEYS;
|
|
@@ -72904,6 +73414,7 @@ exports.NcAlarmModeDelaysSchema = NcAlarmModeDelaysSchema;
|
|
|
72904
73414
|
exports.NcAlarmModeDeviceListSchema = NcAlarmModeDeviceListSchema;
|
|
72905
73415
|
exports.NcAlarmNonBlockingEditSchema = NcAlarmNonBlockingEditSchema;
|
|
72906
73416
|
exports.NcAlarmNonBlockingSchema = NcAlarmNonBlockingSchema;
|
|
73417
|
+
exports.NcAlarmPostTriggeredActionSchema = NcAlarmPostTriggeredActionSchema;
|
|
72907
73418
|
exports.NcAlarmProfileIdInputSchema = NcAlarmProfileIdInputSchema;
|
|
72908
73419
|
exports.NcAlarmProfileMetaSchema = NcAlarmProfileMetaSchema;
|
|
72909
73420
|
exports.NcAlarmProfilesViewSchema = NcAlarmProfilesViewSchema;
|
|
@@ -73085,6 +73596,7 @@ exports.PrivacyMaskPatchSchema = PrivacyMaskPatchSchema;
|
|
|
73085
73596
|
exports.PrivacyMaskRegionSchema = PrivacyMaskRegionSchema;
|
|
73086
73597
|
exports.PrivacyMaskShapeSchema = PrivacyMaskShapeSchema;
|
|
73087
73598
|
exports.PrivacyMaskStatusSchema = PrivacyMaskStatusSchema;
|
|
73599
|
+
exports.ProbeTargetConfigResultSchema = ProbeTargetConfigResultSchema;
|
|
73088
73600
|
exports.ProfileRtspEntrySchema = require_sleep.ProfileRtspEntrySchema;
|
|
73089
73601
|
exports.ProfileSlotSchema = require_sleep.ProfileSlotSchema;
|
|
73090
73602
|
exports.ProfileSlotStatusSchema = require_sleep.ProfileSlotStatusSchema;
|
|
@@ -73487,6 +73999,9 @@ exports.__resetLogChannelRegistryForTests = __resetLogChannelRegistryForTests;
|
|
|
73487
73999
|
exports.accessoriesCapability = accessoriesCapability;
|
|
73488
74000
|
exports.accessoryStableId = accessoryStableId;
|
|
73489
74001
|
exports.actionsForBoundCaps = actionsForBoundCaps;
|
|
74002
|
+
exports.actionsForDevice = actionsForDevice;
|
|
74003
|
+
exports.actionsForDeviceType = actionsForDeviceType;
|
|
74004
|
+
exports.actionsForDevices = actionsForDevices;
|
|
73490
74005
|
exports.activateAlarmProfile = activateAlarmProfile;
|
|
73491
74006
|
exports.addonPagesCapability = addonPagesCapability;
|
|
73492
74007
|
exports.addonPagesSourceCapability = addonPagesSourceCapability;
|
|
@@ -73652,6 +74167,7 @@ exports.deleteAlarmProfile = deleteAlarmProfile;
|
|
|
73652
74167
|
exports.deriveBatteryPresence = deriveBatteryPresence;
|
|
73653
74168
|
exports.deriveCameraSwitches = deriveCameraSwitches;
|
|
73654
74169
|
exports.deriveDetailCropRect = deriveDetailCropRect;
|
|
74170
|
+
exports.derivePostTriggeredAction = derivePostTriggeredAction;
|
|
73655
74171
|
exports.deriveRecordingMode = deriveRecordingMode;
|
|
73656
74172
|
exports.describeComposableCaps = describeComposableCaps;
|
|
73657
74173
|
exports.describeCustomActions = require_sleep.describeCustomActions;
|
|
@@ -73669,6 +74185,7 @@ exports.deviceAdoptionCapability = deviceAdoptionCapability;
|
|
|
73669
74185
|
exports.deviceBackendToFormat = deviceBackendToFormat;
|
|
73670
74186
|
exports.deviceCustomAction = require_sleep.deviceCustomAction;
|
|
73671
74187
|
exports.deviceDiscoveryCapability = deviceDiscoveryCapability;
|
|
74188
|
+
exports.deviceDoFamily = deviceDoFamily;
|
|
73672
74189
|
exports.deviceExportCapability = deviceExportCapability;
|
|
73673
74190
|
exports.deviceExtensionCapability = deviceExtensionCapability;
|
|
73674
74191
|
exports.deviceManagerCapability = deviceManagerCapability;
|
|
@@ -73795,6 +74312,7 @@ exports.isDeviceConfigCap = require_sleep.isDeviceConfigCap;
|
|
|
73795
74312
|
exports.isDeviceScopedCap = require_sleep.isDeviceScopedCap;
|
|
73796
74313
|
exports.isDisplayIconKey = isDisplayIconKey;
|
|
73797
74314
|
exports.isDoActionActuatable = isDoActionActuatable;
|
|
74315
|
+
exports.isDoPickerDeviceType = isDoPickerDeviceType;
|
|
73798
74316
|
exports.isEmbeddingModelFailed = isEmbeddingModelFailed;
|
|
73799
74317
|
exports.isEvent = require_sleep.isEvent;
|
|
73800
74318
|
exports.isEventKindLabelKey = isEventKindLabelKey;
|
|
@@ -74012,10 +74530,12 @@ exports.resolveVariantModelId = resolveVariantModelId;
|
|
|
74012
74530
|
exports.resolveViewableDeviceIds = resolveViewableDeviceIds;
|
|
74013
74531
|
exports.roleSpec = roleSpec;
|
|
74014
74532
|
exports.roomCompositionExample = roomCompositionExample;
|
|
74533
|
+
exports.ruleAutoTriggersAlarm = ruleAutoTriggersAlarm;
|
|
74015
74534
|
exports.ruleBelongsToAlarm = ruleBelongsToAlarm;
|
|
74016
74535
|
exports.ruleDeviceCompatCapNames = ruleDeviceCompatCapNames;
|
|
74017
74536
|
exports.ruleDeviceCompatCapQueries = ruleDeviceCompatCapQueries;
|
|
74018
74537
|
exports.ruleEditorSectionsForKind = ruleEditorSectionsForKind;
|
|
74538
|
+
exports.ruleGatedOnArmedState = ruleGatedOnArmedState;
|
|
74019
74539
|
exports.ruleGroupingApplies = ruleGroupingApplies;
|
|
74020
74540
|
exports.ruleKindOf = ruleKindOf;
|
|
74021
74541
|
exports.ruleKindSpec = ruleKindSpec;
|
|
@@ -74026,6 +74546,7 @@ exports.ruleSeedForSection = ruleSeedForSection;
|
|
|
74026
74546
|
exports.runInferenceStep = runInferenceStep;
|
|
74027
74547
|
exports.runtimeDevices = runtimeDevices;
|
|
74028
74548
|
exports.runtimeStatePolicyFor = runtimeStatePolicyFor;
|
|
74549
|
+
exports.sameDoFamily = sameDoFamily;
|
|
74029
74550
|
exports.sceneMonitorCapability = sceneMonitorCapability;
|
|
74030
74551
|
exports.scheduleForSendTimes = scheduleForSendTimes;
|
|
74031
74552
|
exports.schemaDeclaresAnyField = schemaDeclaresAnyField;
|
|
@@ -74038,6 +74559,7 @@ exports.scriptRunnerCapability = scriptRunnerCapability;
|
|
|
74038
74559
|
exports.searchDisplayIcons = searchDisplayIcons;
|
|
74039
74560
|
exports.secureActuationFor = secureActuationFor;
|
|
74040
74561
|
exports.selectAssignedProfileSlots = require_sleep.selectAssignedProfileSlots;
|
|
74562
|
+
exports.sendTimesForEditor = sendTimesForEditor;
|
|
74041
74563
|
exports.sendTimesOfSchedule = sendTimesOfSchedule;
|
|
74042
74564
|
exports.sensorRaisedOf = sensorRaisedOf;
|
|
74043
74565
|
exports.sensorTransitionNeverFires = sensorTransitionNeverFires;
|