@camstack/addon-notifiers 1.2.622 → 1.2.623
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -1
- package/README.md +24 -8
- package/dist/addon.js +543 -48
- package/dist/addon.mjs +543 -48
- package/i18n/en.json +1 -1
- package/i18n/it.json +1 -1
- package/package.json +3 -3
package/dist/addon.js
CHANGED
|
@@ -5605,7 +5605,7 @@ var ZodIssueCode = {
|
|
|
5605
5605
|
var ZodFirstPartyTypeKind;
|
|
5606
5606
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5607
5607
|
//#endregion
|
|
5608
|
-
//#region ../types/dist/sleep
|
|
5608
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5609
5609
|
/**
|
|
5610
5610
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5611
5611
|
* window to float samples (D455).
|
|
@@ -8962,6 +8962,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8962
8962
|
"filesystem-browse",
|
|
8963
8963
|
"flood",
|
|
8964
8964
|
"gas",
|
|
8965
|
+
"group-active",
|
|
8965
8966
|
"group-commands",
|
|
8966
8967
|
"group-status",
|
|
8967
8968
|
"heating-valve",
|
|
@@ -8984,6 +8985,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8984
8985
|
"login-method",
|
|
8985
8986
|
"media-player",
|
|
8986
8987
|
"mesh-network",
|
|
8988
|
+
"meter",
|
|
8987
8989
|
"metrics-provider",
|
|
8988
8990
|
"model-convert",
|
|
8989
8991
|
"model-distributor",
|
|
@@ -9782,6 +9784,10 @@ Object.freeze({
|
|
|
9782
9784
|
"path": "detected",
|
|
9783
9785
|
"valueType": "boolean"
|
|
9784
9786
|
}],
|
|
9787
|
+
"group-active": [{
|
|
9788
|
+
"path": "active",
|
|
9789
|
+
"valueType": "boolean"
|
|
9790
|
+
}],
|
|
9785
9791
|
"group-status": [
|
|
9786
9792
|
{
|
|
9787
9793
|
"path": "included",
|
|
@@ -10041,6 +10047,10 @@ Object.freeze({
|
|
|
10041
10047
|
]
|
|
10042
10048
|
}
|
|
10043
10049
|
],
|
|
10050
|
+
"meter": [{
|
|
10051
|
+
"path": "value",
|
|
10052
|
+
"valueType": "number"
|
|
10053
|
+
}],
|
|
10044
10054
|
"motion": [
|
|
10045
10055
|
{
|
|
10046
10056
|
"path": "detected",
|
|
@@ -10798,7 +10808,7 @@ function userError(code, params, englishFallback) {
|
|
|
10798
10808
|
return new CamstackError(code, params, englishFallback);
|
|
10799
10809
|
}
|
|
10800
10810
|
//#endregion
|
|
10801
|
-
//#region ../types/dist/err-msg-
|
|
10811
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10802
10812
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10803
10813
|
DeviceType["Camera"] = "camera";
|
|
10804
10814
|
DeviceType["Hub"] = "hub";
|
|
@@ -10892,8 +10902,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10892
10902
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10893
10903
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10894
10904
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10895
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10905
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10906
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10896
10907
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10908
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10909
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10910
|
+
DeviceType["Washer"] = "washer";
|
|
10911
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10912
|
+
DeviceType["Dryer"] = "dryer";
|
|
10897
10913
|
return DeviceType;
|
|
10898
10914
|
}({});
|
|
10899
10915
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -11141,7 +11157,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
11141
11157
|
return DeviceRole;
|
|
11142
11158
|
}({});
|
|
11143
11159
|
//#endregion
|
|
11144
|
-
//#region ../types/dist/composition-
|
|
11160
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
11145
11161
|
/**
|
|
11146
11162
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11147
11163
|
*
|
|
@@ -11456,6 +11472,13 @@ var table = {
|
|
|
11456
11472
|
apply: () => {
|
|
11457
11473
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11458
11474
|
}
|
|
11475
|
+
},
|
|
11476
|
+
schmitt: {
|
|
11477
|
+
minArgs: 3,
|
|
11478
|
+
maxArgs: 5,
|
|
11479
|
+
apply: () => {
|
|
11480
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11481
|
+
}
|
|
11459
11482
|
}
|
|
11460
11483
|
};
|
|
11461
11484
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11897,6 +11920,99 @@ function validateExpressionSource(src) {
|
|
|
11897
11920
|
return null;
|
|
11898
11921
|
}
|
|
11899
11922
|
/**
|
|
11923
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11924
|
+
*
|
|
11925
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11926
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11927
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11928
|
+
*
|
|
11929
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11930
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11931
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11932
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11933
|
+
* can move later without moving the others.
|
|
11934
|
+
*/
|
|
11935
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11936
|
+
var APPLIANCE_KINDS = [
|
|
11937
|
+
"washer",
|
|
11938
|
+
"dryer",
|
|
11939
|
+
"dishwasher"
|
|
11940
|
+
];
|
|
11941
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11942
|
+
/**
|
|
11943
|
+
* Statistics and integrals over a history read (D944).
|
|
11944
|
+
*
|
|
11945
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11946
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11947
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11948
|
+
* as zero. A truncated read is not published.
|
|
11949
|
+
*/
|
|
11950
|
+
var STATISTIC_STATS = [
|
|
11951
|
+
"min",
|
|
11952
|
+
"max",
|
|
11953
|
+
"mean",
|
|
11954
|
+
"sum",
|
|
11955
|
+
"count",
|
|
11956
|
+
"change"
|
|
11957
|
+
];
|
|
11958
|
+
/**
|
|
11959
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11960
|
+
*
|
|
11961
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11962
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11963
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11964
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11965
|
+
*/
|
|
11966
|
+
var MINUTE_MS = 6e4;
|
|
11967
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11968
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11969
|
+
var ROLLING_SPANS = [
|
|
11970
|
+
"1h",
|
|
11971
|
+
"24h",
|
|
11972
|
+
"2d",
|
|
11973
|
+
"7d",
|
|
11974
|
+
"30d",
|
|
11975
|
+
"custom"
|
|
11976
|
+
];
|
|
11977
|
+
var CALENDAR_PERIODS = [
|
|
11978
|
+
"today",
|
|
11979
|
+
"yesterday",
|
|
11980
|
+
"this-week",
|
|
11981
|
+
"this-month"
|
|
11982
|
+
];
|
|
11983
|
+
var RESET_PERIODS = [
|
|
11984
|
+
"never",
|
|
11985
|
+
"daily",
|
|
11986
|
+
"weekly",
|
|
11987
|
+
"monthly"
|
|
11988
|
+
];
|
|
11989
|
+
5 * MINUTE_MS;
|
|
11990
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11991
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11992
|
+
var rollingWindowObject = object({
|
|
11993
|
+
kind: literal("rolling"),
|
|
11994
|
+
span: _enum(ROLLING_SPANS),
|
|
11995
|
+
customMinutes: number().int().min(5).optional()
|
|
11996
|
+
}).check((payload) => {
|
|
11997
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11998
|
+
code: "custom",
|
|
11999
|
+
message: "a custom range needs a duration in minutes",
|
|
12000
|
+
path: ["customMinutes"],
|
|
12001
|
+
input: payload.value
|
|
12002
|
+
});
|
|
12003
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
12004
|
+
code: "custom",
|
|
12005
|
+
message: "only a custom range carries a duration",
|
|
12006
|
+
path: ["customMinutes"],
|
|
12007
|
+
input: payload.value
|
|
12008
|
+
});
|
|
12009
|
+
});
|
|
12010
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
12011
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
12012
|
+
kind: literal("calendar"),
|
|
12013
|
+
period: _enum(CALENDAR_PERIODS)
|
|
12014
|
+
})]);
|
|
12015
|
+
/**
|
|
11900
12016
|
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11901
12017
|
* id. Split out so helper schemas can name it without a cycle through
|
|
11902
12018
|
* `composition.ts` (D659).
|
|
@@ -11922,7 +12038,13 @@ var GROUP_TEMPLATE_IDS = [
|
|
|
11922
12038
|
"occupancy",
|
|
11923
12039
|
"binary",
|
|
11924
12040
|
"switch",
|
|
11925
|
-
"light"
|
|
12041
|
+
"light",
|
|
12042
|
+
"fan",
|
|
12043
|
+
"cover",
|
|
12044
|
+
"valve",
|
|
12045
|
+
"lock",
|
|
12046
|
+
"media-player",
|
|
12047
|
+
"climate"
|
|
11926
12048
|
];
|
|
11927
12049
|
var NUMERIC_AGGREGATES = [
|
|
11928
12050
|
"mean",
|
|
@@ -11952,14 +12074,73 @@ var HelperMemberSchema = object({
|
|
|
11952
12074
|
cap: string().min(1),
|
|
11953
12075
|
fieldPath: string().min(1)
|
|
11954
12076
|
});
|
|
11955
|
-
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
11956
|
-
|
|
11957
|
-
|
|
11958
|
-
|
|
11959
|
-
|
|
11960
|
-
|
|
11961
|
-
|
|
11962
|
-
|
|
12077
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
12078
|
+
object({
|
|
12079
|
+
kind: literal("group"),
|
|
12080
|
+
templateId: GroupTemplateIdSchema,
|
|
12081
|
+
aggregate: AggregateReducerSchema,
|
|
12082
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
12083
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
12084
|
+
active: ActiveCriterionSchema.optional()
|
|
12085
|
+
}),
|
|
12086
|
+
object({
|
|
12087
|
+
kind: literal("appliance"),
|
|
12088
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
12089
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
12090
|
+
thresholdWatts: number().positive(),
|
|
12091
|
+
startDwellMs: number().int().nonnegative(),
|
|
12092
|
+
stopDwellMs: number().int().nonnegative(),
|
|
12093
|
+
member: HelperMemberSchema
|
|
12094
|
+
}),
|
|
12095
|
+
object({
|
|
12096
|
+
kind: literal("statistic"),
|
|
12097
|
+
stat: _enum(STATISTIC_STATS),
|
|
12098
|
+
window: StatisticWindowSchema,
|
|
12099
|
+
source: HelperMemberSchema
|
|
12100
|
+
}),
|
|
12101
|
+
object({
|
|
12102
|
+
kind: literal("integral"),
|
|
12103
|
+
reset: _enum(RESET_PERIODS),
|
|
12104
|
+
output: _enum(["energy", "meter"]),
|
|
12105
|
+
source: HelperMemberSchema
|
|
12106
|
+
}),
|
|
12107
|
+
object({
|
|
12108
|
+
kind: literal("threshold"),
|
|
12109
|
+
source: HelperMemberSchema,
|
|
12110
|
+
high: number(),
|
|
12111
|
+
low: number(),
|
|
12112
|
+
onForMs: number().int().nonnegative(),
|
|
12113
|
+
offForMs: number().int().nonnegative()
|
|
12114
|
+
}),
|
|
12115
|
+
object({
|
|
12116
|
+
kind: literal("arithmetic"),
|
|
12117
|
+
op: _enum([
|
|
12118
|
+
"sum",
|
|
12119
|
+
"difference",
|
|
12120
|
+
"ratio"
|
|
12121
|
+
]),
|
|
12122
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
12123
|
+
}),
|
|
12124
|
+
object({
|
|
12125
|
+
kind: literal("expression"),
|
|
12126
|
+
expr: string().min(1),
|
|
12127
|
+
inputs: array(object({
|
|
12128
|
+
name: string().min(1),
|
|
12129
|
+
member: HelperMemberSchema
|
|
12130
|
+
})).min(1).max(64),
|
|
12131
|
+
output: _enum(["number", "boolean"])
|
|
12132
|
+
}),
|
|
12133
|
+
object({
|
|
12134
|
+
kind: literal("derivative"),
|
|
12135
|
+
window: RollingWindowSchema,
|
|
12136
|
+
per: _enum([
|
|
12137
|
+
"second",
|
|
12138
|
+
"minute",
|
|
12139
|
+
"hour"
|
|
12140
|
+
]),
|
|
12141
|
+
source: HelperMemberSchema
|
|
12142
|
+
})
|
|
12143
|
+
]);
|
|
11963
12144
|
/** A composed device's stableId is this prefix plus the block id. */
|
|
11964
12145
|
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11965
12146
|
/** Longest snippet a `code` source may carry (slice 4). */
|
|
@@ -12020,6 +12201,12 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
|
12020
12201
|
"all"
|
|
12021
12202
|
]),
|
|
12022
12203
|
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
12204
|
+
/**
|
|
12205
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
12206
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
12207
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
12208
|
+
*/
|
|
12209
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
12023
12210
|
/** `value` is the reading; the others are the member counts. */
|
|
12024
12211
|
publish: _enum([
|
|
12025
12212
|
"value",
|
|
@@ -12033,6 +12220,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
|
12033
12220
|
"omit",
|
|
12034
12221
|
"offline"
|
|
12035
12222
|
])
|
|
12223
|
+
}),
|
|
12224
|
+
object({
|
|
12225
|
+
kind: literal("series"),
|
|
12226
|
+
read: CompositionFieldReadSchema,
|
|
12227
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
12228
|
+
publish: _enum([
|
|
12229
|
+
"value",
|
|
12230
|
+
"included",
|
|
12231
|
+
"excluded",
|
|
12232
|
+
"total"
|
|
12233
|
+
]),
|
|
12234
|
+
/**
|
|
12235
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
12236
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
12237
|
+
*/
|
|
12238
|
+
empty: _enum([
|
|
12239
|
+
"null",
|
|
12240
|
+
"omit",
|
|
12241
|
+
"offline"
|
|
12242
|
+
])
|
|
12036
12243
|
})
|
|
12037
12244
|
]);
|
|
12038
12245
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
@@ -17328,7 +17535,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
17328
17535
|
*/
|
|
17329
17536
|
interactiveConnectPath: string().min(1).optional(),
|
|
17330
17537
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
17331
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17538
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17539
|
+
/**
|
|
17540
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17541
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17542
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17543
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17544
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17545
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17546
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17547
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17548
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17549
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17550
|
+
* offers it as the default path; the fields the session fills are
|
|
17551
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17552
|
+
*/
|
|
17553
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
17332
17554
|
}))
|
|
17333
17555
|
});
|
|
17334
17556
|
var ListInputSchema = object({
|
|
@@ -18327,7 +18549,8 @@ var CompositionProblemSchema = object({
|
|
|
18327
18549
|
"native-capability-replace",
|
|
18328
18550
|
"mixed-quantity",
|
|
18329
18551
|
"helper-mismatch",
|
|
18330
|
-
"member-constraint"
|
|
18552
|
+
"member-constraint",
|
|
18553
|
+
"retention"
|
|
18331
18554
|
]),
|
|
18332
18555
|
path: string(),
|
|
18333
18556
|
message: string()
|
|
@@ -18561,13 +18784,17 @@ Object.freeze({
|
|
|
18561
18784
|
latchedAt: {
|
|
18562
18785
|
kind: "fixed",
|
|
18563
18786
|
result: ["number", "null"]
|
|
18787
|
+
},
|
|
18788
|
+
schmitt: {
|
|
18789
|
+
kind: "fixed",
|
|
18790
|
+
result: ["boolean", "null"]
|
|
18564
18791
|
}
|
|
18565
18792
|
});
|
|
18566
18793
|
/**
|
|
18567
18794
|
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18568
18795
|
* Data, not a form default written into the block.
|
|
18569
18796
|
*/
|
|
18570
|
-
var NOW = {
|
|
18797
|
+
var NOW$2 = {
|
|
18571
18798
|
fieldPath: "lastFetchedAt",
|
|
18572
18799
|
expr: "now"
|
|
18573
18800
|
};
|
|
@@ -18581,6 +18808,8 @@ function numeric(input) {
|
|
|
18581
18808
|
family: "numeric",
|
|
18582
18809
|
deviceType: DeviceType.Sensor,
|
|
18583
18810
|
memberDeviceType: DeviceType.Sensor,
|
|
18811
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18812
|
+
activeWhen: void 0,
|
|
18584
18813
|
commandCaps: [],
|
|
18585
18814
|
baseUnit: baseUnitOf(input.quantity),
|
|
18586
18815
|
aggregates: NUMERIC_AGGREGATES,
|
|
@@ -18596,6 +18825,8 @@ function binary(input) {
|
|
|
18596
18825
|
family: "binary",
|
|
18597
18826
|
deviceType: DeviceType.Sensor,
|
|
18598
18827
|
memberDeviceType: DeviceType.Sensor,
|
|
18828
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18829
|
+
activeWhen: void 0,
|
|
18599
18830
|
commandCaps: [],
|
|
18600
18831
|
quantity: "none",
|
|
18601
18832
|
baseUnit: void 0,
|
|
@@ -18613,7 +18844,7 @@ var GROUP_TEMPLATES = [
|
|
|
18613
18844
|
quantity: "temperature",
|
|
18614
18845
|
defaultAggregate: "mean",
|
|
18615
18846
|
empty: "null",
|
|
18616
|
-
companions: [NOW]
|
|
18847
|
+
companions: [NOW$2]
|
|
18617
18848
|
}),
|
|
18618
18849
|
numeric({
|
|
18619
18850
|
id: "humidity",
|
|
@@ -18624,7 +18855,7 @@ var GROUP_TEMPLATES = [
|
|
|
18624
18855
|
quantity: "humidity",
|
|
18625
18856
|
defaultAggregate: "mean",
|
|
18626
18857
|
empty: "null",
|
|
18627
|
-
companions: [NOW]
|
|
18858
|
+
companions: [NOW$2]
|
|
18628
18859
|
}),
|
|
18629
18860
|
numeric({
|
|
18630
18861
|
id: "pressure",
|
|
@@ -18635,7 +18866,7 @@ var GROUP_TEMPLATES = [
|
|
|
18635
18866
|
quantity: "pressure",
|
|
18636
18867
|
defaultAggregate: "mean",
|
|
18637
18868
|
empty: "null",
|
|
18638
|
-
companions: [NOW]
|
|
18869
|
+
companions: [NOW$2]
|
|
18639
18870
|
}),
|
|
18640
18871
|
numeric({
|
|
18641
18872
|
id: "illuminance",
|
|
@@ -18646,7 +18877,7 @@ var GROUP_TEMPLATES = [
|
|
|
18646
18877
|
quantity: "illuminance",
|
|
18647
18878
|
defaultAggregate: "mean",
|
|
18648
18879
|
empty: "null",
|
|
18649
|
-
companions: [NOW]
|
|
18880
|
+
companions: [NOW$2]
|
|
18650
18881
|
}),
|
|
18651
18882
|
numeric({
|
|
18652
18883
|
id: "power",
|
|
@@ -18657,7 +18888,7 @@ var GROUP_TEMPLATES = [
|
|
|
18657
18888
|
quantity: "power",
|
|
18658
18889
|
defaultAggregate: "sum",
|
|
18659
18890
|
empty: "omit",
|
|
18660
|
-
companions: [NOW]
|
|
18891
|
+
companions: [NOW$2]
|
|
18661
18892
|
}),
|
|
18662
18893
|
numeric({
|
|
18663
18894
|
id: "energy",
|
|
@@ -18668,7 +18899,7 @@ var GROUP_TEMPLATES = [
|
|
|
18668
18899
|
quantity: "energy",
|
|
18669
18900
|
defaultAggregate: "sum",
|
|
18670
18901
|
empty: "omit",
|
|
18671
|
-
companions: [NOW]
|
|
18902
|
+
companions: [NOW$2]
|
|
18672
18903
|
}),
|
|
18673
18904
|
numeric({
|
|
18674
18905
|
id: "battery",
|
|
@@ -18703,7 +18934,7 @@ var GROUP_TEMPLATES = [
|
|
|
18703
18934
|
quantity: "device",
|
|
18704
18935
|
defaultAggregate: "mean",
|
|
18705
18936
|
empty: "null",
|
|
18706
|
-
companions: [NOW]
|
|
18937
|
+
companions: [NOW$2]
|
|
18707
18938
|
}),
|
|
18708
18939
|
binary({
|
|
18709
18940
|
id: "motion",
|
|
@@ -18797,6 +19028,11 @@ var GROUP_TEMPLATES = [
|
|
|
18797
19028
|
summary: "On when at least one switch is on, or when all of them are. Offline and unknown members are left out of that decision, never read as off, and still receive the command.",
|
|
18798
19029
|
deviceType: DeviceType.Switch,
|
|
18799
19030
|
outputCap: "switch",
|
|
19031
|
+
outputField: "on",
|
|
19032
|
+
member: {
|
|
19033
|
+
cap: "switch",
|
|
19034
|
+
fieldPath: "on"
|
|
19035
|
+
},
|
|
18800
19036
|
commandCaps: ["switch"]
|
|
18801
19037
|
}),
|
|
18802
19038
|
actuator({
|
|
@@ -18804,34 +19040,136 @@ var GROUP_TEMPLATES = [
|
|
|
18804
19040
|
summary: "On when at least one light is on, or when all of them are. Brightness and colour are offered only when every member has them. A command is not sent to a member that lacks it.",
|
|
18805
19041
|
deviceType: DeviceType.Light,
|
|
18806
19042
|
outputCap: "switch",
|
|
19043
|
+
outputField: "on",
|
|
19044
|
+
member: {
|
|
19045
|
+
cap: "switch",
|
|
19046
|
+
fieldPath: "on"
|
|
19047
|
+
},
|
|
18807
19048
|
commandCaps: [
|
|
18808
19049
|
"switch",
|
|
18809
19050
|
"brightness",
|
|
18810
19051
|
"color"
|
|
18811
19052
|
]
|
|
19053
|
+
}),
|
|
19054
|
+
actuator({
|
|
19055
|
+
id: "fan",
|
|
19056
|
+
summary: "On when at least one fan is on, or when all of them are. Speed, preset, direction and oscillation are offered only when every fan has them. A command is not sent to a fan that lacks it.",
|
|
19057
|
+
deviceType: DeviceType.Fan,
|
|
19058
|
+
outputCap: "switch",
|
|
19059
|
+
outputField: "on",
|
|
19060
|
+
member: {
|
|
19061
|
+
cap: "switch",
|
|
19062
|
+
fieldPath: "on"
|
|
19063
|
+
},
|
|
19064
|
+
commandCaps: ["switch", "fan-control"]
|
|
19065
|
+
}),
|
|
19066
|
+
actuator({
|
|
19067
|
+
id: "cover",
|
|
19068
|
+
summary: "Open when at least one cover is open or part-open, or only when all of them are. Position and tilt are offered only when every cover has them. A cover that reports nothing is left out, never read as closed.",
|
|
19069
|
+
deviceType: DeviceType.Cover,
|
|
19070
|
+
outputCap: "group-active",
|
|
19071
|
+
outputField: "active",
|
|
19072
|
+
member: {
|
|
19073
|
+
cap: "cover",
|
|
19074
|
+
fieldPath: "state"
|
|
19075
|
+
},
|
|
19076
|
+
activeWhen: [
|
|
19077
|
+
"open",
|
|
19078
|
+
"opening",
|
|
19079
|
+
"stopped"
|
|
19080
|
+
],
|
|
19081
|
+
commandCaps: ["cover"]
|
|
19082
|
+
}),
|
|
19083
|
+
actuator({
|
|
19084
|
+
id: "valve",
|
|
19085
|
+
summary: "Open when at least one valve is open or part-open, or only when all of them are. Position is offered only when every valve has it. A valve that reports nothing is left out, never read as closed.",
|
|
19086
|
+
deviceType: DeviceType.Valve,
|
|
19087
|
+
outputCap: "group-active",
|
|
19088
|
+
outputField: "active",
|
|
19089
|
+
member: {
|
|
19090
|
+
cap: "valve",
|
|
19091
|
+
fieldPath: "state"
|
|
19092
|
+
},
|
|
19093
|
+
activeWhen: [
|
|
19094
|
+
"open",
|
|
19095
|
+
"opening",
|
|
19096
|
+
"stopped"
|
|
19097
|
+
],
|
|
19098
|
+
commandCaps: ["valve"]
|
|
19099
|
+
}),
|
|
19100
|
+
actuator({
|
|
19101
|
+
id: "lock",
|
|
19102
|
+
summary: "Locked when at least one lock is locked, or only when all of them are. A jammed or moving lock is not locked. Locking is one tap; unlocking the group needs a confirmation every time, and nothing is sent without it.",
|
|
19103
|
+
deviceType: DeviceType.Lock,
|
|
19104
|
+
outputCap: "group-active",
|
|
19105
|
+
outputField: "active",
|
|
19106
|
+
member: {
|
|
19107
|
+
cap: "lock-control",
|
|
19108
|
+
fieldPath: "state"
|
|
19109
|
+
},
|
|
19110
|
+
activeWhen: ["locked"],
|
|
19111
|
+
commandCaps: ["lock-control"]
|
|
19112
|
+
}),
|
|
19113
|
+
actuator({
|
|
19114
|
+
id: "media-player",
|
|
19115
|
+
summary: "Playing when at least one player is playing, or only when all of them are. Volume is offered only when every player has it. A player that reports nothing is left out, never read as stopped.",
|
|
19116
|
+
deviceType: DeviceType.MediaPlayer,
|
|
19117
|
+
outputCap: "group-active",
|
|
19118
|
+
outputField: "active",
|
|
19119
|
+
member: {
|
|
19120
|
+
cap: "media-player",
|
|
19121
|
+
fieldPath: "state"
|
|
19122
|
+
},
|
|
19123
|
+
activeWhen: ["playing", "buffering"],
|
|
19124
|
+
commandCaps: ["media-player"]
|
|
19125
|
+
}),
|
|
19126
|
+
actuator({
|
|
19127
|
+
id: "climate",
|
|
19128
|
+
summary: "Running when at least one thermostat or air conditioner is not off, or only when all of them are. Target temperature and fan are offered only when every device has them. A device that reports nothing is left out, never read as off.",
|
|
19129
|
+
deviceType: DeviceType.Thermostat,
|
|
19130
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
19131
|
+
outputCap: "group-active",
|
|
19132
|
+
outputField: "active",
|
|
19133
|
+
member: {
|
|
19134
|
+
cap: "climate-control",
|
|
19135
|
+
fieldPath: "mode"
|
|
19136
|
+
},
|
|
19137
|
+
activeWhen: [
|
|
19138
|
+
"heat",
|
|
19139
|
+
"cool",
|
|
19140
|
+
"auto",
|
|
19141
|
+
"heat_cool",
|
|
19142
|
+
"fan_only",
|
|
19143
|
+
"dry"
|
|
19144
|
+
],
|
|
19145
|
+
commandCaps: ["climate-control"]
|
|
18812
19146
|
})
|
|
18813
19147
|
];
|
|
18814
19148
|
function actuator(input) {
|
|
18815
19149
|
return {
|
|
18816
|
-
|
|
19150
|
+
id: input.id,
|
|
19151
|
+
summary: input.summary,
|
|
19152
|
+
deviceType: input.deviceType,
|
|
19153
|
+
outputCap: input.outputCap,
|
|
19154
|
+
outputField: input.outputField,
|
|
19155
|
+
commandCaps: input.commandCaps,
|
|
18817
19156
|
family: "actuator",
|
|
18818
19157
|
role: void 0,
|
|
18819
19158
|
memberDeviceType: input.deviceType,
|
|
18820
|
-
|
|
19159
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
19160
|
+
activeWhen: input.activeWhen,
|
|
18821
19161
|
quantity: "none",
|
|
18822
19162
|
baseUnit: void 0,
|
|
18823
19163
|
aggregates: BINARY_AGGREGATES,
|
|
18824
19164
|
defaultAggregate: "any",
|
|
18825
19165
|
empty: "offline",
|
|
18826
|
-
accept: [
|
|
18827
|
-
cap: "switch",
|
|
18828
|
-
fieldPath: "on"
|
|
18829
|
-
}],
|
|
19166
|
+
accept: [input.member],
|
|
18830
19167
|
companions: [CHANGED]
|
|
18831
19168
|
};
|
|
18832
19169
|
}
|
|
18833
19170
|
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18834
19171
|
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
19172
|
+
DeviceType.Camera;
|
|
18835
19173
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18836
19174
|
/**
|
|
18837
19175
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -43846,7 +44184,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43846
44184
|
});
|
|
43847
44185
|
/**
|
|
43848
44186
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43849
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44187
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43850
44188
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43851
44189
|
* the originating provider config (mode + sourcePort) so the
|
|
43852
44190
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -46511,7 +46849,20 @@ var NcRuleInputSchema = object({
|
|
|
46511
46849
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46512
46850
|
* path does not run Zod defaults.
|
|
46513
46851
|
*/
|
|
46514
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46852
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46853
|
+
/**
|
|
46854
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46855
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46856
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46857
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46858
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46859
|
+
*
|
|
46860
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46861
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46862
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46863
|
+
* `false`, so it needs no `clear` key.
|
|
46864
|
+
*/
|
|
46865
|
+
askVerdict: boolean().optional()
|
|
46515
46866
|
});
|
|
46516
46867
|
/**
|
|
46517
46868
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56968,7 +57319,7 @@ var BatteryStatusSchema = object({
|
|
|
56968
57319
|
*/
|
|
56969
57320
|
binary: boolean().optional().meta({ label: "Binary indicator" })
|
|
56970
57321
|
});
|
|
56971
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
|
|
57322
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
|
|
56972
57323
|
method(object({
|
|
56973
57324
|
deviceId: number(),
|
|
56974
57325
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
@@ -58712,7 +59063,13 @@ results: array(object({
|
|
|
58712
59063
|
/** Ms epoch of the attempt. */
|
|
58713
59064
|
at: number()
|
|
58714
59065
|
})) });
|
|
58715
|
-
DeviceType.Switch, DeviceType.Light;
|
|
59066
|
+
DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
59067
|
+
object({
|
|
59068
|
+
active: boolean().meta({ label: "Active" }),
|
|
59069
|
+
/** Ms epoch when the slice was last updated. */
|
|
59070
|
+
lastChangedAt: number()
|
|
59071
|
+
});
|
|
59072
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
|
|
58716
59073
|
object({
|
|
58717
59074
|
/** Members whose current value entered the aggregate. */
|
|
58718
59075
|
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
@@ -58730,7 +59087,7 @@ object({
|
|
|
58730
59087
|
label: "Members"
|
|
58731
59088
|
}))
|
|
58732
59089
|
});
|
|
58733
|
-
DeviceType.Sensor, DeviceType.Switch, DeviceType.Light;
|
|
59090
|
+
DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
58734
59091
|
object({
|
|
58735
59092
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
58736
59093
|
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
@@ -59637,7 +59994,14 @@ DeviceType.Lock, method(object({
|
|
|
59637
59994
|
auth: "protected"
|
|
59638
59995
|
}), method(object({
|
|
59639
59996
|
deviceId: number().int().nonnegative(),
|
|
59640
|
-
code: string().min(1).optional()
|
|
59997
|
+
code: string().min(1).optional(),
|
|
59998
|
+
/**
|
|
59999
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
60000
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
60001
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
60002
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
60003
|
+
*/
|
|
60004
|
+
confirm: boolean().optional()
|
|
59641
60005
|
}), _void(), {
|
|
59642
60006
|
kind: "mutation",
|
|
59643
60007
|
auth: "protected"
|
|
@@ -59645,6 +60009,11 @@ DeviceType.Lock, method(object({
|
|
|
59645
60009
|
kind: "mutation",
|
|
59646
60010
|
auth: "protected"
|
|
59647
60011
|
});
|
|
60012
|
+
object({
|
|
60013
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
60014
|
+
lastFetchedAt: number()
|
|
60015
|
+
});
|
|
60016
|
+
DeviceType.Sensor;
|
|
59648
60017
|
/**
|
|
59649
60018
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
59650
60019
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
@@ -61552,9 +61921,9 @@ object({
|
|
|
61552
61921
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
61553
61922
|
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
61554
61923
|
/** Voltage in volts. */
|
|
61555
|
-
volts: number().optional().meta(readingMeta("voltage")),
|
|
61924
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
61556
61925
|
/** Current in amperes. */
|
|
61557
|
-
amps: number().optional().meta(readingMeta("current")),
|
|
61926
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
61558
61927
|
/** Apparent power in volt-amperes. */
|
|
61559
61928
|
va: number().optional().meta(readingMeta("apparent-power")),
|
|
61560
61929
|
/** Power factor (0..1) if reported. */
|
|
@@ -61562,7 +61931,23 @@ object({
|
|
|
61562
61931
|
/** Ms epoch when the slice was last updated. */
|
|
61563
61932
|
lastFetchedAt: number()
|
|
61564
61933
|
});
|
|
61565
|
-
|
|
61934
|
+
[
|
|
61935
|
+
DeviceType.Sensor,
|
|
61936
|
+
DeviceType.Switch,
|
|
61937
|
+
DeviceType.Light,
|
|
61938
|
+
DeviceType.Fan,
|
|
61939
|
+
DeviceType.Climate,
|
|
61940
|
+
DeviceType.Thermostat,
|
|
61941
|
+
DeviceType.Humidifier,
|
|
61942
|
+
DeviceType.WaterHeater,
|
|
61943
|
+
DeviceType.MediaPlayer,
|
|
61944
|
+
DeviceType.Washer,
|
|
61945
|
+
DeviceType.Dryer,
|
|
61946
|
+
DeviceType.Dishwasher,
|
|
61947
|
+
DeviceType.Vacuum,
|
|
61948
|
+
DeviceType.LawnMower,
|
|
61949
|
+
DeviceType.PetFeeder
|
|
61950
|
+
].filter((type) => type !== DeviceType.Sensor);
|
|
61566
61951
|
/**
|
|
61567
61952
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
61568
61953
|
* on `DeviceType.Presence`. Read-only — no setters: presence is
|
|
@@ -62009,7 +62394,7 @@ object({
|
|
|
62009
62394
|
phase: string().nullable()
|
|
62010
62395
|
});
|
|
62011
62396
|
Object.values(DeviceType);
|
|
62012
|
-
DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
62397
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
62013
62398
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
62014
62399
|
kind: "mutation",
|
|
62015
62400
|
auth: "admin"
|
|
@@ -64048,7 +64433,7 @@ object({
|
|
|
64048
64433
|
/** Ms epoch of the last state change. Useful for UI "X minutes ago". */
|
|
64049
64434
|
lastChangedAt: number()
|
|
64050
64435
|
});
|
|
64051
|
-
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
|
|
64436
|
+
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
|
|
64052
64437
|
deviceId: number(),
|
|
64053
64438
|
on: boolean()
|
|
64054
64439
|
}), _void(), {
|
|
@@ -65740,8 +66125,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
65740
66125
|
kind: "mutation",
|
|
65741
66126
|
auth: "admin"
|
|
65742
66127
|
});
|
|
66128
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
65743
66129
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
65744
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Camera, DeviceType.Camera, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
66130
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
65745
66131
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
65746
66132
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
65747
66133
|
new Set(CAP_NAMES);
|
|
@@ -65794,7 +66180,7 @@ var AccessoryKind = {
|
|
|
65794
66180
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
65795
66181
|
};
|
|
65796
66182
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
65797
|
-
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
|
|
66183
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer;
|
|
65798
66184
|
new Set(Object.values(DeviceType));
|
|
65799
66185
|
Object.freeze({
|
|
65800
66186
|
"accessories.getStatus": {
|
|
@@ -69017,6 +69403,13 @@ Object.freeze({
|
|
|
69017
69403
|
access: "view",
|
|
69018
69404
|
role: "viewer"
|
|
69019
69405
|
},
|
|
69406
|
+
"groupActive.getStatus": {
|
|
69407
|
+
capName: "group-active",
|
|
69408
|
+
capScope: "device",
|
|
69409
|
+
addonId: null,
|
|
69410
|
+
access: "view",
|
|
69411
|
+
role: "viewer"
|
|
69412
|
+
},
|
|
69020
69413
|
"groupCommands.getStatus": {
|
|
69021
69414
|
capName: "group-commands",
|
|
69022
69415
|
capScope: "device",
|
|
@@ -69983,6 +70376,13 @@ Object.freeze({
|
|
|
69983
70376
|
access: "create",
|
|
69984
70377
|
role: "admin"
|
|
69985
70378
|
},
|
|
70379
|
+
"meter.getStatus": {
|
|
70380
|
+
capName: "meter",
|
|
70381
|
+
capScope: "device",
|
|
70382
|
+
addonId: null,
|
|
70383
|
+
access: "view",
|
|
70384
|
+
role: "viewer"
|
|
70385
|
+
},
|
|
69986
70386
|
"metricsProvider.collectSnapshot": {
|
|
69987
70387
|
capName: "metrics-provider",
|
|
69988
70388
|
capScope: "system",
|
|
@@ -78081,7 +78481,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
78081
78481
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
78082
78482
|
icon: "square"
|
|
78083
78483
|
}
|
|
78084
|
-
}
|
|
78484
|
+
},
|
|
78485
|
+
overrides: { byType: {
|
|
78486
|
+
[DeviceType.Washer]: {
|
|
78487
|
+
state: { running: {
|
|
78488
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
78489
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
78490
|
+
} },
|
|
78491
|
+
events: {
|
|
78492
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
78493
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
78494
|
+
}
|
|
78495
|
+
},
|
|
78496
|
+
[DeviceType.Dryer]: {
|
|
78497
|
+
state: { running: {
|
|
78498
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
78499
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
78500
|
+
} },
|
|
78501
|
+
events: {
|
|
78502
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
78503
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
78504
|
+
}
|
|
78505
|
+
},
|
|
78506
|
+
[DeviceType.Dishwasher]: {
|
|
78507
|
+
state: { running: {
|
|
78508
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
78509
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
78510
|
+
} },
|
|
78511
|
+
events: {
|
|
78512
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
78513
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
78514
|
+
}
|
|
78515
|
+
}
|
|
78516
|
+
} }
|
|
78085
78517
|
},
|
|
78086
78518
|
update: {
|
|
78087
78519
|
scope: "device",
|
|
@@ -78853,6 +79285,10 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78853
79285
|
icon: "flame"
|
|
78854
79286
|
}]
|
|
78855
79287
|
},
|
|
79288
|
+
"group-active": {
|
|
79289
|
+
scope: "device",
|
|
79290
|
+
noun: t("Group state", "Stato del gruppo")
|
|
79291
|
+
},
|
|
78856
79292
|
"group-commands": {
|
|
78857
79293
|
scope: "device",
|
|
78858
79294
|
noun: t("Group command", "Comando di gruppo")
|
|
@@ -78909,6 +79345,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78909
79345
|
}],
|
|
78910
79346
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
78911
79347
|
},
|
|
79348
|
+
meter: {
|
|
79349
|
+
scope: "device",
|
|
79350
|
+
noun: t("Meter", "Contatore"),
|
|
79351
|
+
state: [{
|
|
79352
|
+
kind: "numeric",
|
|
79353
|
+
field: "value",
|
|
79354
|
+
quantity: t("the total", "il totale"),
|
|
79355
|
+
label: t("Total", "Totale"),
|
|
79356
|
+
icon: "gauge"
|
|
79357
|
+
}]
|
|
79358
|
+
},
|
|
78912
79359
|
"numeric-sensor": {
|
|
78913
79360
|
scope: "device",
|
|
78914
79361
|
noun: t("Sensor", "Sensore"),
|
|
@@ -79381,8 +79828,47 @@ function projectAction(cap, action) {
|
|
|
79381
79828
|
};
|
|
79382
79829
|
}
|
|
79383
79830
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
79384
|
-
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
|
|
79831
|
+
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer;
|
|
79385
79832
|
DeviceFeature.BatteryOperated;
|
|
79833
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
79834
|
+
var HA_AS = "a power sensor (device_class power). Home Assistant has no laundry domain. running-state stays unexported until a null reading can be published as unavailable.";
|
|
79835
|
+
var HOMEKIT_REASON = "HomeKit has no laundry-appliance service. The export tab would pair an accessory with nothing on it: running-state is withheld until a null reading can be unavailable, and power is not a HomeKit service this export honours.";
|
|
79836
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
79837
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
79838
|
+
var MATTER_REASON = "No Matter export is built. The closest device types are Laundry Washer (0x0073) and Laundry Dryer (0x0074); a power threshold is not the Laundry Washer Mode cluster.";
|
|
79839
|
+
function withheld(reason) {
|
|
79840
|
+
return {
|
|
79841
|
+
[DeviceType.Washer]: {
|
|
79842
|
+
exported: false,
|
|
79843
|
+
reason
|
|
79844
|
+
},
|
|
79845
|
+
[DeviceType.Dryer]: {
|
|
79846
|
+
exported: false,
|
|
79847
|
+
reason
|
|
79848
|
+
},
|
|
79849
|
+
[DeviceType.Dishwasher]: {
|
|
79850
|
+
exported: false,
|
|
79851
|
+
reason
|
|
79852
|
+
}
|
|
79853
|
+
};
|
|
79854
|
+
}
|
|
79855
|
+
function offered(received) {
|
|
79856
|
+
return {
|
|
79857
|
+
[DeviceType.Washer]: {
|
|
79858
|
+
exported: true,
|
|
79859
|
+
as: received
|
|
79860
|
+
},
|
|
79861
|
+
[DeviceType.Dryer]: {
|
|
79862
|
+
exported: true,
|
|
79863
|
+
as: received
|
|
79864
|
+
},
|
|
79865
|
+
[DeviceType.Dishwasher]: {
|
|
79866
|
+
exported: true,
|
|
79867
|
+
as: received
|
|
79868
|
+
}
|
|
79869
|
+
};
|
|
79870
|
+
}
|
|
79871
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
79386
79872
|
Object.freeze({
|
|
79387
79873
|
"accessories.getStatus": [{
|
|
79388
79874
|
name: "deviceId",
|
|
@@ -80349,6 +80835,11 @@ Object.freeze({
|
|
|
80349
80835
|
form: "single",
|
|
80350
80836
|
optional: false
|
|
80351
80837
|
}],
|
|
80838
|
+
"groupActive.getStatus": [{
|
|
80839
|
+
name: "deviceId",
|
|
80840
|
+
form: "single",
|
|
80841
|
+
optional: false
|
|
80842
|
+
}],
|
|
80352
80843
|
"groupCommands.getStatus": [{
|
|
80353
80844
|
name: "deviceId",
|
|
80354
80845
|
form: "single",
|
|
@@ -80559,6 +81050,11 @@ Object.freeze({
|
|
|
80559
81050
|
form: "single",
|
|
80560
81051
|
optional: false
|
|
80561
81052
|
}],
|
|
81053
|
+
"meter.getStatus": [{
|
|
81054
|
+
name: "deviceId",
|
|
81055
|
+
form: "single",
|
|
81056
|
+
optional: false
|
|
81057
|
+
}],
|
|
80562
81058
|
"motion.getStatus": [{
|
|
80563
81059
|
name: "deviceId",
|
|
80564
81060
|
form: "single",
|
|
@@ -82166,7 +82662,6 @@ Object.freeze({
|
|
|
82166
82662
|
"network-access": "ingress",
|
|
82167
82663
|
"smtp-provider": "email"
|
|
82168
82664
|
});
|
|
82169
|
-
DeviceType.Camera;
|
|
82170
82665
|
/**
|
|
82171
82666
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
82172
82667
|
* `z.infer`, they do not restate the shape.
|
|
@@ -83915,7 +84410,7 @@ function buildEmailDescriptor(providers = []) {
|
|
|
83915
84410
|
id: "email",
|
|
83916
84411
|
title: "Email",
|
|
83917
84412
|
titleKey: "notifiers:emailDescriptor.s_email.title",
|
|
83918
|
-
description: "Send via a Connectivity → Email provider (Google
|
|
84413
|
+
description: "Send via a Connectivity → Email provider (Google or Email (SMTP)). Install and Verify a provider first.",
|
|
83919
84414
|
descriptionKey: "notifiers:emailDescriptor.s_email.description",
|
|
83920
84415
|
fields: [
|
|
83921
84416
|
{
|
|
@@ -83932,7 +84427,7 @@ function buildEmailDescriptor(providers = []) {
|
|
|
83932
84427
|
key: "smtpAddonId",
|
|
83933
84428
|
label: "Email provider",
|
|
83934
84429
|
labelKey: "notifiers:emailDescriptor.s_email.smtpAddonId.label",
|
|
83935
|
-
description: options.length === 0 ? "No Email provider installed. Open Connectivity → Email, install Google
|
|
84430
|
+
description: options.length === 0 ? "No Email provider installed. Open Connectivity → Email, install Google or Email (SMTP), then Verify." : "Which Connectivity → Email entry delivers this target. Verify it under Connectivity → Email if the label says not verified.",
|
|
83936
84431
|
required: true,
|
|
83937
84432
|
options
|
|
83938
84433
|
},
|
|
@@ -86232,7 +86727,7 @@ var HTTP_NOTIFIER_ADAPTERS = [
|
|
|
86232
86727
|
*/
|
|
86233
86728
|
function buildNotifierAdapters(smtp) {
|
|
86234
86729
|
const emailSmtp = smtp ?? { async sendEmail() {
|
|
86235
|
-
throw new Error("email: no smtp-provider client — install Google
|
|
86730
|
+
throw new Error("email: no smtp-provider client — install Google or Email (SMTP) under Connectivity → Email and Verify it");
|
|
86236
86731
|
} };
|
|
86237
86732
|
return [...HTTP_NOTIFIER_ADAPTERS, createEmailAdapter(emailSmtp)];
|
|
86238
86733
|
}
|