@camstack/addon-provider-homematic 1.2.161 → 1.2.162
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 +6 -0
- package/dist/addon.js +721 -15
- package/dist/addon.mjs +721 -15
- package/package.json +1 -1
package/dist/addon.mjs
CHANGED
|
@@ -5590,7 +5590,7 @@ var ZodIssueCode = {
|
|
|
5590
5590
|
var ZodFirstPartyTypeKind;
|
|
5591
5591
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5592
5592
|
//#endregion
|
|
5593
|
-
//#region ../types/dist/sleep-
|
|
5593
|
+
//#region ../types/dist/sleep-C_u6cEAJ.mjs
|
|
5594
5594
|
/**
|
|
5595
5595
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5596
5596
|
* window to float samples (D455).
|
|
@@ -8983,6 +8983,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8983
8983
|
"image-settings",
|
|
8984
8984
|
"integrations",
|
|
8985
8985
|
"intercom",
|
|
8986
|
+
"ir-transmitter",
|
|
8986
8987
|
"keychain",
|
|
8987
8988
|
"keychain-admin",
|
|
8988
8989
|
"lawn-mower-control",
|
|
@@ -9011,6 +9012,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9011
9012
|
"network-link",
|
|
9012
9013
|
"network-quality",
|
|
9013
9014
|
"node-certificates",
|
|
9015
|
+
"node-removal-hook",
|
|
9014
9016
|
"nodes",
|
|
9015
9017
|
"notification-output",
|
|
9016
9018
|
"notification-rules",
|
|
@@ -9041,6 +9043,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9041
9043
|
"recording-onboard",
|
|
9042
9044
|
"recording-signal",
|
|
9043
9045
|
"records",
|
|
9046
|
+
"remote",
|
|
9044
9047
|
"running-state",
|
|
9045
9048
|
"scene-monitor",
|
|
9046
9049
|
"script-runner",
|
|
@@ -9064,6 +9067,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9064
9067
|
"system",
|
|
9065
9068
|
"tamper",
|
|
9066
9069
|
"temperature-sensor",
|
|
9070
|
+
"template",
|
|
9067
9071
|
"terminal-session",
|
|
9068
9072
|
"toast",
|
|
9069
9073
|
"training",
|
|
@@ -10004,6 +10008,11 @@ Object.freeze({
|
|
|
10004
10008
|
"standby"
|
|
10005
10009
|
]
|
|
10006
10010
|
},
|
|
10011
|
+
{
|
|
10012
|
+
"path": "stateSource",
|
|
10013
|
+
"valueType": "enum",
|
|
10014
|
+
"enumValues": ["reported", "assumed"]
|
|
10015
|
+
},
|
|
10007
10016
|
{
|
|
10008
10017
|
"path": "volumeLevel",
|
|
10009
10018
|
"valueType": "number"
|
|
@@ -10230,6 +10239,11 @@ Object.freeze({
|
|
|
10230
10239
|
"path": "batteryPower",
|
|
10231
10240
|
"valueType": "number"
|
|
10232
10241
|
},
|
|
10242
|
+
{
|
|
10243
|
+
"path": "powerSource",
|
|
10244
|
+
"valueType": "enum",
|
|
10245
|
+
"enumValues": ["mains", "battery"]
|
|
10246
|
+
},
|
|
10233
10247
|
{
|
|
10234
10248
|
"path": "desiccantLeftDays",
|
|
10235
10249
|
"valueType": "number"
|
|
@@ -10274,6 +10288,18 @@ Object.freeze({
|
|
|
10274
10288
|
{
|
|
10275
10289
|
"path": "volume",
|
|
10276
10290
|
"valueType": "number"
|
|
10291
|
+
},
|
|
10292
|
+
{
|
|
10293
|
+
"path": "lastFeedGrams",
|
|
10294
|
+
"valueType": "number"
|
|
10295
|
+
},
|
|
10296
|
+
{
|
|
10297
|
+
"path": "lastFeedHopper1",
|
|
10298
|
+
"valueType": "number"
|
|
10299
|
+
},
|
|
10300
|
+
{
|
|
10301
|
+
"path": "lastFeedHopper2",
|
|
10302
|
+
"valueType": "number"
|
|
10277
10303
|
}
|
|
10278
10304
|
],
|
|
10279
10305
|
"power-meter": [
|
|
@@ -10813,7 +10839,7 @@ object({
|
|
|
10813
10839
|
params: record(string(), union([string(), number()])).optional()
|
|
10814
10840
|
});
|
|
10815
10841
|
//#endregion
|
|
10816
|
-
//#region ../types/dist/err-msg-
|
|
10842
|
+
//#region ../types/dist/err-msg-BCdlR2Li.mjs
|
|
10817
10843
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10818
10844
|
DeviceType["Camera"] = "camera";
|
|
10819
10845
|
DeviceType["Hub"] = "hub";
|
|
@@ -11159,6 +11185,9 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
11159
11185
|
/** Fallback when the notifier service name doesn't match a known
|
|
11160
11186
|
* pattern. */
|
|
11161
11187
|
DeviceRole["GenericNotifier"] = "generic-notifier";
|
|
11188
|
+
/** Emits a pulse train (infrared or RF) on request — the `ir-transmitter`
|
|
11189
|
+
* cap. A `DeviceType.Generic` device. */
|
|
11190
|
+
DeviceRole["IrTransmitter"] = "ir-transmitter";
|
|
11162
11191
|
return DeviceRole;
|
|
11163
11192
|
}({});
|
|
11164
11193
|
/**
|
|
@@ -11172,7 +11201,7 @@ function errMsg(err) {
|
|
|
11172
11201
|
return String(err);
|
|
11173
11202
|
}
|
|
11174
11203
|
//#endregion
|
|
11175
|
-
//#region ../types/dist/composition-
|
|
11204
|
+
//#region ../types/dist/composition-bIBW5_13.mjs
|
|
11176
11205
|
/**
|
|
11177
11206
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11178
11207
|
*
|
|
@@ -16582,9 +16611,21 @@ var AlertSeveritySchema = _enum([
|
|
|
16582
16611
|
"error",
|
|
16583
16612
|
"critical"
|
|
16584
16613
|
]);
|
|
16614
|
+
/**
|
|
16615
|
+
* An action that RUNS something instead of going somewhere: the admin UI calls
|
|
16616
|
+
* the addon's custom action (`addons.custom`) with exactly these fields. The
|
|
16617
|
+
* producer owns the meaning; the UI knows nothing about the addon or the kind.
|
|
16618
|
+
*/
|
|
16619
|
+
var AlertActionInvokeSchema = object({
|
|
16620
|
+
addonId: string().min(1),
|
|
16621
|
+
action: string().min(1),
|
|
16622
|
+
input: record(string(), unknown()).optional()
|
|
16623
|
+
});
|
|
16624
|
+
/** An action has `href` (a link) OR `invoke` (a button that runs a custom action). */
|
|
16585
16625
|
var AlertActionSchema = object({
|
|
16586
16626
|
label: string(),
|
|
16587
16627
|
href: string().optional(),
|
|
16628
|
+
invoke: AlertActionInvokeSchema.optional(),
|
|
16588
16629
|
/**
|
|
16589
16630
|
* How `href` is followed. Absent / `app`: an admin-ui route (client-side).
|
|
16590
16631
|
* `server`: a route the HUB serves (an addon HTTP route such as an OAuth
|
|
@@ -19239,12 +19280,13 @@ var CHANGED = {
|
|
|
19239
19280
|
expr: "now"
|
|
19240
19281
|
};
|
|
19241
19282
|
function numeric(input) {
|
|
19283
|
+
const { alsoFrom, ...base } = input;
|
|
19242
19284
|
return {
|
|
19243
|
-
...
|
|
19285
|
+
...base,
|
|
19244
19286
|
family: "numeric",
|
|
19245
19287
|
deviceType: DeviceType.Sensor,
|
|
19246
19288
|
memberDeviceType: DeviceType.Sensor,
|
|
19247
|
-
memberDeviceTypes: [DeviceType.Sensor],
|
|
19289
|
+
memberDeviceTypes: [DeviceType.Sensor, ...alsoFrom?.deviceTypes ?? []],
|
|
19248
19290
|
activeWhen: void 0,
|
|
19249
19291
|
commandCaps: [],
|
|
19250
19292
|
baseUnit: baseUnitOf(input.quantity),
|
|
@@ -19252,9 +19294,10 @@ function numeric(input) {
|
|
|
19252
19294
|
accept: [{
|
|
19253
19295
|
cap: input.outputCap,
|
|
19254
19296
|
fieldPath: input.outputField
|
|
19255
|
-
}]
|
|
19297
|
+
}, ...alsoFrom === void 0 ? [] : [alsoFrom.accept]]
|
|
19256
19298
|
};
|
|
19257
19299
|
}
|
|
19300
|
+
var CLIMATE_DEVICES = [DeviceType.Thermostat, DeviceType.Climate];
|
|
19258
19301
|
function binary(input) {
|
|
19259
19302
|
return {
|
|
19260
19303
|
...input,
|
|
@@ -19280,7 +19323,14 @@ var GROUP_TEMPLATES = [
|
|
|
19280
19323
|
quantity: "temperature",
|
|
19281
19324
|
defaultAggregate: "mean",
|
|
19282
19325
|
empty: "null",
|
|
19283
|
-
companions: [NOW$2]
|
|
19326
|
+
companions: [NOW$2],
|
|
19327
|
+
alsoFrom: {
|
|
19328
|
+
deviceTypes: CLIMATE_DEVICES,
|
|
19329
|
+
accept: {
|
|
19330
|
+
cap: "climate-control",
|
|
19331
|
+
fieldPath: "currentTemp"
|
|
19332
|
+
}
|
|
19333
|
+
}
|
|
19284
19334
|
}),
|
|
19285
19335
|
numeric({
|
|
19286
19336
|
id: "humidity",
|
|
@@ -19291,7 +19341,14 @@ var GROUP_TEMPLATES = [
|
|
|
19291
19341
|
quantity: "humidity",
|
|
19292
19342
|
defaultAggregate: "mean",
|
|
19293
19343
|
empty: "null",
|
|
19294
|
-
companions: [NOW$2]
|
|
19344
|
+
companions: [NOW$2],
|
|
19345
|
+
alsoFrom: {
|
|
19346
|
+
deviceTypes: CLIMATE_DEVICES,
|
|
19347
|
+
accept: {
|
|
19348
|
+
cap: "climate-control",
|
|
19349
|
+
fieldPath: "currentHumidity"
|
|
19350
|
+
}
|
|
19351
|
+
}
|
|
19295
19352
|
}),
|
|
19296
19353
|
numeric({
|
|
19297
19354
|
id: "pressure",
|
|
@@ -43258,6 +43315,14 @@ method(object({
|
|
|
43258
43315
|
kind: "mutation",
|
|
43259
43316
|
auth: "admin"
|
|
43260
43317
|
});
|
|
43318
|
+
method(object({
|
|
43319
|
+
nodeId: string().min(1),
|
|
43320
|
+
/** Epoch ms the node was forgotten (the tombstone's `removedAt`). */
|
|
43321
|
+
removedAt: number()
|
|
43322
|
+
}), object({ counts: record(string(), number().int().nonnegative()) }), {
|
|
43323
|
+
kind: "mutation",
|
|
43324
|
+
auth: "admin"
|
|
43325
|
+
});
|
|
43261
43326
|
/**
|
|
43262
43327
|
* `device-removal-hook` — the reliable way an addon learns a device was DELETED,
|
|
43263
43328
|
* so it can delete what it keeps for that device (D865).
|
|
@@ -43905,6 +43970,17 @@ var LlmProfileSchema = object({
|
|
|
43905
43970
|
* field in its editor only when its descriptor lists it in `profileFields`. */
|
|
43906
43971
|
topK: number().int().positive().optional(),
|
|
43907
43972
|
maxTokens: number().int().positive().optional(),
|
|
43973
|
+
/** How hard the model "thinks" before it answers. Omitted = the model's own
|
|
43974
|
+
* default. `off` matters for structured output: a thinking model can spend
|
|
43975
|
+
* the whole completion on reasoning and return an empty `content`. Carried
|
|
43976
|
+
* only by the wires that have it — a kind offers the field in its editor
|
|
43977
|
+
* only when its descriptor lists it in `profileFields`. */
|
|
43978
|
+
reasoningEffort: _enum([
|
|
43979
|
+
"off",
|
|
43980
|
+
"low",
|
|
43981
|
+
"medium",
|
|
43982
|
+
"high"
|
|
43983
|
+
]).optional(),
|
|
43908
43984
|
/** Prompt context window. Advisory for cloud kinds (they enforce their own). */
|
|
43909
43985
|
contextLength: number().int().positive().optional(),
|
|
43910
43986
|
/** Default system prompt. A caller's `system` REPLACES it (never appends —
|
|
@@ -43943,6 +44019,7 @@ var LlmProfileFieldSchema = _enum([
|
|
|
43943
44019
|
"topP",
|
|
43944
44020
|
"topK",
|
|
43945
44021
|
"maxTokens",
|
|
44022
|
+
"reasoningEffort",
|
|
43946
44023
|
"contextLength",
|
|
43947
44024
|
"systemPrompt",
|
|
43948
44025
|
"timeoutMs",
|
|
@@ -45193,6 +45270,43 @@ var NotificationActionSchema = object({
|
|
|
45193
45270
|
*/
|
|
45194
45271
|
mode: _enum(["navigate", "background"]).optional()
|
|
45195
45272
|
});
|
|
45273
|
+
/** A delivery parameter value: what a notifier declared it takes. */
|
|
45274
|
+
var DeliveryParamValueSchema = union([
|
|
45275
|
+
string(),
|
|
45276
|
+
number(),
|
|
45277
|
+
boolean()
|
|
45278
|
+
]);
|
|
45279
|
+
/**
|
|
45280
|
+
* One extra delivery parameter a notifier KIND declares (D938). A rule that
|
|
45281
|
+
* addresses a target of that kind may set it; a kind that declares nothing is
|
|
45282
|
+
* never handed one. The admin UI derives its control from this descriptor —
|
|
45283
|
+
* no editor knows a service by name.
|
|
45284
|
+
*
|
|
45285
|
+
* Optional fields are `.optional()`, never `.default()` (a Zod default does not
|
|
45286
|
+
* run on the addon cap path).
|
|
45287
|
+
*/
|
|
45288
|
+
var DeliveryParamSchema = object({
|
|
45289
|
+
key: string().min(1),
|
|
45290
|
+
label: string(),
|
|
45291
|
+
/** i18n key of the label, resolved by the declaring addon's namespace. */
|
|
45292
|
+
labelKey: string().optional(),
|
|
45293
|
+
type: _enum([
|
|
45294
|
+
"enum",
|
|
45295
|
+
"number",
|
|
45296
|
+
"boolean",
|
|
45297
|
+
"string"
|
|
45298
|
+
]),
|
|
45299
|
+
/** `enum` only: the closed set of accepted values. */
|
|
45300
|
+
options: array(object({
|
|
45301
|
+
value: string(),
|
|
45302
|
+
label: string()
|
|
45303
|
+
})).optional(),
|
|
45304
|
+
/** `number` only. */
|
|
45305
|
+
min: number().optional(),
|
|
45306
|
+
max: number().optional(),
|
|
45307
|
+
/** What the notifier does when the rule sets nothing; shown as the placeholder. */
|
|
45308
|
+
default: DeliveryParamValueSchema.optional()
|
|
45309
|
+
});
|
|
45196
45310
|
/**
|
|
45197
45311
|
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
45198
45312
|
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
@@ -45215,7 +45329,13 @@ var NotificationSchema = object({
|
|
|
45215
45329
|
tag: string().optional(),
|
|
45216
45330
|
deviceId: number().optional(),
|
|
45217
45331
|
eventId: string().optional(),
|
|
45218
|
-
metadata: record(string(), unknown()).optional()
|
|
45332
|
+
metadata: record(string(), unknown()).optional(),
|
|
45333
|
+
/**
|
|
45334
|
+
* Values for the parameters the target's kind DECLARES in
|
|
45335
|
+
* {@link TargetKindSchema} `deliveryParams`. Already validated against the
|
|
45336
|
+
* declaration by the sender; a notifier reads only the keys it declared.
|
|
45337
|
+
*/
|
|
45338
|
+
delivery: record(string(), DeliveryParamValueSchema).optional()
|
|
45219
45339
|
});
|
|
45220
45340
|
/** One declared native severity/priority level for a kind. */
|
|
45221
45341
|
var TargetKindLevelSchema = object({
|
|
@@ -45321,6 +45441,11 @@ var TargetKindSchema = object({
|
|
|
45321
45441
|
*/
|
|
45322
45442
|
destinationKeys: array(string()).optional(),
|
|
45323
45443
|
supportsDiscovery: boolean(),
|
|
45444
|
+
/**
|
|
45445
|
+
* Extra delivery parameters a rule may set for a target of this kind (D938).
|
|
45446
|
+
* Absent = none; the rule editor then offers nothing.
|
|
45447
|
+
*/
|
|
45448
|
+
deliveryParams: array(DeliveryParamSchema).optional(),
|
|
45324
45449
|
caps: TargetKindCapsSchema
|
|
45325
45450
|
});
|
|
45326
45451
|
/**
|
|
@@ -57612,7 +57737,9 @@ var ManifestShapeSchema = object({
|
|
|
57612
57737
|
icon: string().optional()
|
|
57613
57738
|
}).optional(),
|
|
57614
57739
|
protected: boolean().optional(),
|
|
57615
|
-
removable: boolean().optional()
|
|
57740
|
+
removable: boolean().optional(),
|
|
57741
|
+
/** Declared Integrations-page block (mirror of `AddonDeclaration.integrationSection`). */
|
|
57742
|
+
integrationSection: _enum(["system", "providers"]).optional()
|
|
57616
57743
|
});
|
|
57617
57744
|
var AddonProcessSchema = object({
|
|
57618
57745
|
pid: number().optional(),
|
|
@@ -58741,11 +58868,373 @@ onBrightnessChanged: { data: object({
|
|
|
58741
58868
|
minIntervalMs: 0
|
|
58742
58869
|
} } }
|
|
58743
58870
|
};
|
|
58871
|
+
/**
|
|
58872
|
+
* The role vocabulary of a remote (D963): what a button MEANS, independent of
|
|
58873
|
+
* how it is wired. A layout template places buttons by role; a device binds a
|
|
58874
|
+
* role to an action; an exporter asks for a role by name. Roles are shared so
|
|
58875
|
+
* one layout fits every appliance and one voice command fits every binding.
|
|
58876
|
+
*
|
|
58877
|
+
* A role outside this list is `custom:<key>` — the operator's own button (a
|
|
58878
|
+
* SmartIR source, a channel preset). The key is a lowercase slug.
|
|
58879
|
+
*/
|
|
58880
|
+
var REMOTE_KNOWN_ROLES = [
|
|
58881
|
+
"power",
|
|
58882
|
+
"power_on",
|
|
58883
|
+
"power_off",
|
|
58884
|
+
"volume_up",
|
|
58885
|
+
"volume_down",
|
|
58886
|
+
"mute",
|
|
58887
|
+
"channel_up",
|
|
58888
|
+
"channel_down",
|
|
58889
|
+
"up",
|
|
58890
|
+
"down",
|
|
58891
|
+
"left",
|
|
58892
|
+
"right",
|
|
58893
|
+
"ok",
|
|
58894
|
+
"back",
|
|
58895
|
+
"home",
|
|
58896
|
+
"menu",
|
|
58897
|
+
"info",
|
|
58898
|
+
"guide",
|
|
58899
|
+
"exit",
|
|
58900
|
+
"input",
|
|
58901
|
+
"play",
|
|
58902
|
+
"pause",
|
|
58903
|
+
"play_pause",
|
|
58904
|
+
"stop",
|
|
58905
|
+
"next",
|
|
58906
|
+
"previous",
|
|
58907
|
+
"fast_forward",
|
|
58908
|
+
"rewind",
|
|
58909
|
+
"digit_0",
|
|
58910
|
+
"digit_1",
|
|
58911
|
+
"digit_2",
|
|
58912
|
+
"digit_3",
|
|
58913
|
+
"digit_4",
|
|
58914
|
+
"digit_5",
|
|
58915
|
+
"digit_6",
|
|
58916
|
+
"digit_7",
|
|
58917
|
+
"digit_8",
|
|
58918
|
+
"digit_9"
|
|
58919
|
+
];
|
|
58920
|
+
var CUSTOM_KEY_RE = /^[a-z0-9][a-z0-9_]{0,47}$/;
|
|
58921
|
+
var KNOWN_ROLES = new Set(REMOTE_KNOWN_ROLES);
|
|
58922
|
+
function isRemoteKnownRole(value) {
|
|
58923
|
+
return KNOWN_ROLES.has(value);
|
|
58924
|
+
}
|
|
58925
|
+
function isRemoteCustomKey(key) {
|
|
58926
|
+
return CUSTOM_KEY_RE.test(key);
|
|
58927
|
+
}
|
|
58928
|
+
/** The key of a `custom:<key>` role, or null for any other string. */
|
|
58929
|
+
function customKeyOfRole(role) {
|
|
58930
|
+
if (!role.startsWith("custom:")) return null;
|
|
58931
|
+
const key = role.slice(7);
|
|
58932
|
+
return isRemoteCustomKey(key) ? key : null;
|
|
58933
|
+
}
|
|
58934
|
+
function isRemoteRole(value) {
|
|
58935
|
+
return isRemoteKnownRole(value) || customKeyOfRole(value) !== null;
|
|
58936
|
+
}
|
|
58937
|
+
var RemoteRoleSchema = string().refine(isRemoteRole, { message: "a role is one of the known roles or custom:<key> (lowercase letters, digits, _)" });
|
|
58938
|
+
var RemoteBindingSchema = object({ action: AutomationCapStepSchema.extend({ deviceId: number().int().nonnegative() }) });
|
|
58939
|
+
var RemoteCustomButtonSchema = object({
|
|
58940
|
+
/** The slug after `custom:` in the role. */
|
|
58941
|
+
key: string().refine(isRemoteCustomKey, { message: "a lowercase slug" }),
|
|
58942
|
+
/** What the operator calls it, and what a voice command may name. */
|
|
58943
|
+
name: string().min(1).max(60)
|
|
58944
|
+
});
|
|
58945
|
+
var RemotePowerModeSchema = _enum(["toggle", "discrete"]);
|
|
58946
|
+
var RemoteConfigSchema = object({
|
|
58947
|
+
layoutTemplateId: string().min(1).nullable(),
|
|
58948
|
+
/**
|
|
58949
|
+
* The transmitter device new bindings and an import send through. A binding
|
|
58950
|
+
* names its own device, so one command may override it.
|
|
58951
|
+
*/
|
|
58952
|
+
defaultTransmitterId: number().int().nonnegative().nullable().default(null),
|
|
58953
|
+
/** Keyed by role. A role with no entry falls back to the native cap. */
|
|
58954
|
+
bindings: record(string(), RemoteBindingSchema),
|
|
58955
|
+
customButtons: array(RemoteCustomButtonSchema).max(100),
|
|
58956
|
+
power: object({ mode: RemotePowerModeSchema })
|
|
58957
|
+
}).superRefine((config, ctx) => {
|
|
58958
|
+
const roles = Object.keys(config.bindings);
|
|
58959
|
+
if (roles.length > 200) ctx.addIssue({
|
|
58960
|
+
code: "custom",
|
|
58961
|
+
message: "too many bindings",
|
|
58962
|
+
path: ["bindings"]
|
|
58963
|
+
});
|
|
58964
|
+
for (const role of roles) if (!isRemoteRole(role)) ctx.addIssue({
|
|
58965
|
+
code: "custom",
|
|
58966
|
+
message: `"${role}" is not a role`,
|
|
58967
|
+
path: ["bindings", role]
|
|
58968
|
+
});
|
|
58969
|
+
const keys = /* @__PURE__ */ new Set();
|
|
58970
|
+
config.customButtons.forEach((button, index) => {
|
|
58971
|
+
if (keys.has(button.key)) ctx.addIssue({
|
|
58972
|
+
code: "custom",
|
|
58973
|
+
message: `custom button "${button.key}" is listed twice`,
|
|
58974
|
+
path: [
|
|
58975
|
+
"customButtons",
|
|
58976
|
+
index,
|
|
58977
|
+
"key"
|
|
58978
|
+
]
|
|
58979
|
+
});
|
|
58980
|
+
keys.add(button.key);
|
|
58981
|
+
});
|
|
58982
|
+
for (const role of roles) {
|
|
58983
|
+
const key = customKeyOfRole(role);
|
|
58984
|
+
if (key !== null && !keys.has(key)) ctx.addIssue({
|
|
58985
|
+
code: "custom",
|
|
58986
|
+
message: `${role} is bound but has no entry in customButtons`,
|
|
58987
|
+
path: ["bindings", role]
|
|
58988
|
+
});
|
|
58989
|
+
}
|
|
58990
|
+
});
|
|
58991
|
+
object({
|
|
58992
|
+
power: object({
|
|
58993
|
+
state: _enum(["on", "off"]),
|
|
58994
|
+
at: number()
|
|
58995
|
+
}).nullable(),
|
|
58996
|
+
muted: object({
|
|
58997
|
+
value: boolean(),
|
|
58998
|
+
at: number()
|
|
58999
|
+
}).nullable()
|
|
59000
|
+
});
|
|
59001
|
+
var RemoteLayoutButtonSchema = object({
|
|
59002
|
+
id: string().min(1).max(40),
|
|
59003
|
+
/** 0-based grid position. */
|
|
59004
|
+
row: number().int().min(0).max(24),
|
|
59005
|
+
col: number().int().min(0).max(24),
|
|
59006
|
+
rowSpan: number().int().min(1).max(24),
|
|
59007
|
+
colSpan: number().int().min(1).max(24),
|
|
59008
|
+
icon: string().min(1).max(60).optional(),
|
|
59009
|
+
label: string().min(1).max(40).optional(),
|
|
59010
|
+
role: RemoteRoleSchema
|
|
59011
|
+
});
|
|
59012
|
+
object({
|
|
59013
|
+
columns: number().int().min(1).max(24),
|
|
59014
|
+
rows: number().int().min(1).max(24),
|
|
59015
|
+
buttons: array(RemoteLayoutButtonSchema).max(200)
|
|
59016
|
+
}).superRefine((grid, ctx) => {
|
|
59017
|
+
const ids = /* @__PURE__ */ new Set();
|
|
59018
|
+
const taken = /* @__PURE__ */ new Map();
|
|
59019
|
+
grid.buttons.forEach((button, index) => {
|
|
59020
|
+
if (ids.has(button.id)) ctx.addIssue({
|
|
59021
|
+
code: "custom",
|
|
59022
|
+
message: `button id "${button.id}" is used twice`,
|
|
59023
|
+
path: [
|
|
59024
|
+
"buttons",
|
|
59025
|
+
index,
|
|
59026
|
+
"id"
|
|
59027
|
+
]
|
|
59028
|
+
});
|
|
59029
|
+
ids.add(button.id);
|
|
59030
|
+
if (button.row + button.rowSpan > grid.rows || button.col + button.colSpan > grid.columns) {
|
|
59031
|
+
ctx.addIssue({
|
|
59032
|
+
code: "custom",
|
|
59033
|
+
message: `button "${button.id}" leaves the grid`,
|
|
59034
|
+
path: ["buttons", index]
|
|
59035
|
+
});
|
|
59036
|
+
return;
|
|
59037
|
+
}
|
|
59038
|
+
for (let r = button.row; r < button.row + button.rowSpan; r += 1) for (let c = button.col; c < button.col + button.colSpan; c += 1) {
|
|
59039
|
+
const cell = `${r}:${c}`;
|
|
59040
|
+
const other = taken.get(cell);
|
|
59041
|
+
if (other !== void 0) {
|
|
59042
|
+
ctx.addIssue({
|
|
59043
|
+
code: "custom",
|
|
59044
|
+
message: `buttons "${other}" and "${button.id}" overlap`,
|
|
59045
|
+
path: ["buttons", index]
|
|
59046
|
+
});
|
|
59047
|
+
return;
|
|
59048
|
+
}
|
|
59049
|
+
taken.set(cell, button.id);
|
|
59050
|
+
}
|
|
59051
|
+
});
|
|
59052
|
+
});
|
|
59053
|
+
var RemoteBoundCommandSchema = object({
|
|
59054
|
+
role: RemoteRoleSchema,
|
|
59055
|
+
/** The operator's name for a custom button; absent for a known role. */
|
|
59056
|
+
label: string().optional(),
|
|
59057
|
+
custom: boolean()
|
|
59058
|
+
});
|
|
59059
|
+
var RemoteCommandListSchema = object({
|
|
59060
|
+
layoutTemplateId: string().nullable(),
|
|
59061
|
+
power: object({ mode: RemotePowerModeSchema }),
|
|
59062
|
+
/** Only the roles that are BOUND — the ones a press can reach. */
|
|
59063
|
+
commands: array(RemoteBoundCommandSchema)
|
|
59064
|
+
});
|
|
59065
|
+
var RemoteRefusalReasonSchema = _enum([
|
|
59066
|
+
"no-remote",
|
|
59067
|
+
"unbound-role",
|
|
59068
|
+
"action-failed"
|
|
59069
|
+
]);
|
|
59070
|
+
var RemoteSendResultSchema = discriminatedUnion("status", [
|
|
59071
|
+
object({
|
|
59072
|
+
status: literal("sent"),
|
|
59073
|
+
/** How many times the action ran. */
|
|
59074
|
+
sends: number().int().min(1)
|
|
59075
|
+
}),
|
|
59076
|
+
object({
|
|
59077
|
+
status: literal("skipped"),
|
|
59078
|
+
reason: literal("already-in-state")
|
|
59079
|
+
}),
|
|
59080
|
+
object({
|
|
59081
|
+
status: literal("refused"),
|
|
59082
|
+
reason: RemoteRefusalReasonSchema,
|
|
59083
|
+
detail: string().optional()
|
|
59084
|
+
})
|
|
59085
|
+
]);
|
|
59086
|
+
var RemoteMediaCommandSchema = _enum([
|
|
59087
|
+
"play",
|
|
59088
|
+
"pause",
|
|
59089
|
+
"stop",
|
|
59090
|
+
"next",
|
|
59091
|
+
"previous",
|
|
59092
|
+
"setMute",
|
|
59093
|
+
"selectSource"
|
|
59094
|
+
]);
|
|
59095
|
+
/** A send result, or `not-routed`: the role is not bound, so the native cap answers. */
|
|
59096
|
+
var RemoteMediaCommandResultSchema = discriminatedUnion("status", [...RemoteSendResultSchema.options, object({ status: literal("not-routed") })]);
|
|
59097
|
+
var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status: literal("saved") }), object({
|
|
59098
|
+
status: literal("refused"),
|
|
59099
|
+
reason: _enum(["unknown-template", "not-a-media-player"]),
|
|
59100
|
+
detail: string()
|
|
59101
|
+
})]);
|
|
59102
|
+
var deviceInput = object({ deviceId: number().int().nonnegative() });
|
|
59103
|
+
DeviceType.MediaPlayer;
|
|
59104
|
+
method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
|
|
59105
|
+
kind: "mutation",
|
|
59106
|
+
auth: "admin"
|
|
59107
|
+
}), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
|
|
59108
|
+
role: RemoteRoleSchema,
|
|
59109
|
+
/** Sends in a row (volume steps). */
|
|
59110
|
+
repeat: number().int().min(1).max(50).default(1)
|
|
59111
|
+
}), RemoteSendResultSchema, {
|
|
59112
|
+
kind: "mutation",
|
|
59113
|
+
auth: "protected"
|
|
59114
|
+
}), method(deviceInput.extend({
|
|
59115
|
+
command: RemoteMediaCommandSchema,
|
|
59116
|
+
muted: boolean().optional(),
|
|
59117
|
+
source: string().optional(),
|
|
59118
|
+
repeat: number().int().min(1).max(50).default(1)
|
|
59119
|
+
}), RemoteMediaCommandResultSchema, {
|
|
59120
|
+
kind: "mutation",
|
|
59121
|
+
auth: "protected"
|
|
59122
|
+
});
|
|
59123
|
+
var TemplateKindSchema = _enum(["remote"]);
|
|
59124
|
+
/**
|
|
59125
|
+
* template — the generic store of reusable, named operator data (D963). A
|
|
59126
|
+
* record is `{ id, kind, name, payload }`; the kinds (today only `remote`, the
|
|
59127
|
+
* button grid of a remote) and the schema each payload must satisfy are
|
|
59128
|
+
* declared by the system in `template-kinds.ts`. Nothing here is specific to a
|
|
59129
|
+
* kind: the engine validates a payload against its kind's schema and, on a
|
|
59130
|
+
* delete, asks the kind's owner whether anything still points at the record.
|
|
59131
|
+
*
|
|
59132
|
+
* Every refusal is a typed result — a UI says "unknown kind" or names the
|
|
59133
|
+
* devices that still use a template, without parsing text.
|
|
59134
|
+
*/
|
|
59135
|
+
var TemplateRecordSchema = object({
|
|
59136
|
+
id: string().min(1),
|
|
59137
|
+
kind: TemplateKindSchema,
|
|
59138
|
+
name: string().min(1).max(120),
|
|
59139
|
+
/** Shaped by the kind; `checkTemplatePayload(kind, payload)` reads it. */
|
|
59140
|
+
payload: unknown(),
|
|
59141
|
+
createdAt: number(),
|
|
59142
|
+
updatedAt: number()
|
|
59143
|
+
});
|
|
59144
|
+
var TemplateWriteResultSchema = discriminatedUnion("status", [object({
|
|
59145
|
+
status: literal("saved"),
|
|
59146
|
+
template: TemplateRecordSchema
|
|
59147
|
+
}), object({
|
|
59148
|
+
status: literal("refused"),
|
|
59149
|
+
reason: _enum(["invalid-payload", "not-found"]),
|
|
59150
|
+
detail: string()
|
|
59151
|
+
})]);
|
|
59152
|
+
/** A device still pointing at a template. */
|
|
59153
|
+
var TemplateUserSchema = object({
|
|
59154
|
+
deviceId: number().int().nonnegative(),
|
|
59155
|
+
name: string()
|
|
59156
|
+
});
|
|
59157
|
+
var TemplateDeleteResultSchema = discriminatedUnion("status", [
|
|
59158
|
+
object({ status: literal("deleted") }),
|
|
59159
|
+
object({ status: literal("not-found") }),
|
|
59160
|
+
object({
|
|
59161
|
+
status: literal("in-use"),
|
|
59162
|
+
devices: array(TemplateUserSchema).min(1)
|
|
59163
|
+
})
|
|
59164
|
+
]);
|
|
59165
|
+
method(object({ kind: TemplateKindSchema.optional() }), array(TemplateRecordSchema), { auth: "protected" }), method(object({ id: string().min(1) }), TemplateRecordSchema.nullable(), { auth: "protected" }), method(object({
|
|
59166
|
+
kind: TemplateKindSchema,
|
|
59167
|
+
name: string().min(1).max(120),
|
|
59168
|
+
payload: unknown()
|
|
59169
|
+
}), TemplateWriteResultSchema, {
|
|
59170
|
+
kind: "mutation",
|
|
59171
|
+
auth: "admin"
|
|
59172
|
+
}), method(object({
|
|
59173
|
+
id: string().min(1),
|
|
59174
|
+
name: string().min(1).max(120).optional(),
|
|
59175
|
+
payload: unknown().optional()
|
|
59176
|
+
}), TemplateWriteResultSchema, {
|
|
59177
|
+
kind: "mutation",
|
|
59178
|
+
auth: "admin"
|
|
59179
|
+
}), method(object({ id: string().min(1) }), TemplateDeleteResultSchema, {
|
|
59180
|
+
kind: "mutation",
|
|
59181
|
+
auth: "admin"
|
|
59182
|
+
});
|
|
58744
59183
|
DeviceType.Button, method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
58745
59184
|
kind: "mutation",
|
|
58746
59185
|
auth: "protected"
|
|
58747
59186
|
});
|
|
58748
59187
|
/**
|
|
59188
|
+
* A pulse train in signed microseconds: mark (+) first, then space (-), strictly
|
|
59189
|
+
* alternating, no zeros, 2..1024 entries.
|
|
59190
|
+
*/
|
|
59191
|
+
var IrTimingsSchema = array(number().int()).min(2).max(1024).superRefine((timings, ctx) => {
|
|
59192
|
+
timings.forEach((value, index) => {
|
|
59193
|
+
const expectMark = index % 2 === 0;
|
|
59194
|
+
if (value === 0 || value > 0 !== expectMark) ctx.addIssue({
|
|
59195
|
+
code: "custom",
|
|
59196
|
+
message: `timing ${index} must be a non-zero ${expectMark ? "mark (positive)" : "space (negative)"}`,
|
|
59197
|
+
path: [index]
|
|
59198
|
+
});
|
|
59199
|
+
});
|
|
59200
|
+
});
|
|
59201
|
+
/** Per-command transmit options. Every key is optional; a transmitter applies what it can. */
|
|
59202
|
+
var TransmitSettingsSchema = object({
|
|
59203
|
+
carrierHz: number().int().positive().optional(),
|
|
59204
|
+
dutyCyclePercent: number().int().min(1).max(100).optional(),
|
|
59205
|
+
repeat: number().int().min(0).max(20).optional(),
|
|
59206
|
+
repeatDelayMs: number().int().min(0).optional()
|
|
59207
|
+
});
|
|
59208
|
+
/** The setting keys a transmitter may declare as settable (`getInfo.settable`). */
|
|
59209
|
+
var TransmitSettingKeySchema = _enum([
|
|
59210
|
+
"carrierHz",
|
|
59211
|
+
"dutyCyclePercent",
|
|
59212
|
+
"repeat",
|
|
59213
|
+
"repeatDelayMs"
|
|
59214
|
+
]);
|
|
59215
|
+
var IrMediumSchema = _enum(["ir", "rf"]);
|
|
59216
|
+
var IrSendResultSchema = object({
|
|
59217
|
+
ok: literal(true),
|
|
59218
|
+
/** Settings the transmitter could not apply; the train was still sent. */
|
|
59219
|
+
ignoredSettings: array(string())
|
|
59220
|
+
});
|
|
59221
|
+
var IrTransmitterInfoSchema = object({
|
|
59222
|
+
media: array(IrMediumSchema),
|
|
59223
|
+
settable: array(TransmitSettingKeySchema),
|
|
59224
|
+
maxTimings: number().int().positive()
|
|
59225
|
+
});
|
|
59226
|
+
DeviceType.Generic, method(object({
|
|
59227
|
+
deviceId: number().int().nonnegative(),
|
|
59228
|
+
timings: IrTimingsSchema,
|
|
59229
|
+
settings: TransmitSettingsSchema.optional()
|
|
59230
|
+
}), IrSendResultSchema, {
|
|
59231
|
+
kind: "mutation",
|
|
59232
|
+
auth: "protected"
|
|
59233
|
+
}), method(object({ deviceId: number().int().nonnegative() }), IrTransmitterInfoSchema, {
|
|
59234
|
+
kind: "query",
|
|
59235
|
+
auth: "protected"
|
|
59236
|
+
});
|
|
59237
|
+
/**
|
|
58749
59238
|
* `calendar-source` — collection cap exposing per-provider calendars and
|
|
58750
59239
|
* their events. Every addon that contributes calendars (Home Assistant,
|
|
58751
59240
|
* a future Google Calendar addon, …) registers a provider here. The hub
|
|
@@ -62842,9 +63331,35 @@ var MediaInfoSchema = object({
|
|
|
62842
63331
|
/** Optional cover-art / thumbnail URL. */
|
|
62843
63332
|
imageUrl: string().optional()
|
|
62844
63333
|
});
|
|
63334
|
+
/**
|
|
63335
|
+
* Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
|
|
63336
|
+
* the device said so. `assumed`: the driver has no feedback (infrared) and
|
|
63337
|
+
* tracks what it last SENT; it moves only after a send was accepted, and a
|
|
63338
|
+
* human at the real remote makes it wrong. A UI shows an assumed value as a
|
|
63339
|
+
* guess, never as a reading.
|
|
63340
|
+
*/
|
|
63341
|
+
var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
|
|
63342
|
+
/** The fields of a media-player status a driver can only guess. */
|
|
63343
|
+
var MediaPlayerAssumedFieldSchema = _enum([
|
|
63344
|
+
"state",
|
|
63345
|
+
"volumeLevel",
|
|
63346
|
+
"isMuted",
|
|
63347
|
+
"source"
|
|
63348
|
+
]);
|
|
62845
63349
|
var MediaPlayerStatusSchema = object({
|
|
62846
63350
|
/** Playback lifecycle state. */
|
|
62847
63351
|
state: MediaPlayerStateSchema,
|
|
63352
|
+
/**
|
|
63353
|
+
* Whether the state fields are readings or the driver's own bookkeeping.
|
|
63354
|
+
* A slice written before this field existed parses as `reported`.
|
|
63355
|
+
*/
|
|
63356
|
+
stateSource: MediaPlayerStateSourceSchema.default("reported"),
|
|
63357
|
+
/**
|
|
63358
|
+
* Which fields are the driver's own guess. `stateSource` is `assumed` when
|
|
63359
|
+
* this is not empty; a field not listed here is a reading even then (power
|
|
63360
|
+
* from a running-state source, mute guessed from the last send).
|
|
63361
|
+
*/
|
|
63362
|
+
assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
|
|
62848
63363
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
62849
63364
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
62850
63365
|
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
@@ -64772,9 +65287,14 @@ var PetFeederStatusSchema = object({
|
|
|
64772
65287
|
* (`device_class: problem`, on = low). True when the tank reports empty,
|
|
64773
65288
|
* or, on a dual-hopper model, when EITHER hopper is empty. */
|
|
64774
65289
|
lowFood: boolean(),
|
|
64775
|
-
/** Battery charge 0..100 (%).
|
|
64776
|
-
*
|
|
65290
|
+
/** Battery charge 0..100 (%). On a feeder running on `mains` this is the
|
|
65291
|
+
* BACKUP battery's charge, not the power source. Null when the device has
|
|
65292
|
+
* no battery reading. */
|
|
64777
65293
|
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
65294
|
+
/** What the feeder is powered from right now: `mains` (plugged in, the
|
|
65295
|
+
* battery is only a backup) or `battery`. Null when the device does not
|
|
65296
|
+
* report it. */
|
|
65297
|
+
powerSource: _enum(["mains", "battery"]).nullable(),
|
|
64778
65298
|
/**
|
|
64779
65299
|
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
64780
65300
|
* Providers convert from the days the feeder reports. Null when the
|
|
@@ -64802,6 +65322,14 @@ var PetFeederStatusSchema = object({
|
|
|
64802
65322
|
feedSound: boolean(),
|
|
64803
65323
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
64804
65324
|
volume: number().meta(readingMeta("none")),
|
|
65325
|
+
/** Portion (grams) of the last manual feed sent from a single-hopper
|
|
65326
|
+
* stepper — the default the next manual feed starts from. Persisted per
|
|
65327
|
+
* device by the provider; null until a manual feed has been sent. */
|
|
65328
|
+
lastFeedGrams: gramsPortion.nullable(),
|
|
65329
|
+
/** Hopper-1 portion of the last manual feed (dual-hopper); null until sent. */
|
|
65330
|
+
lastFeedHopper1: gramsPortion.nullable(),
|
|
65331
|
+
/** Hopper-2 portion of the last manual feed (dual-hopper); null until sent. */
|
|
65332
|
+
lastFeedHopper2: gramsPortion.nullable(),
|
|
64805
65333
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
64806
65334
|
lastFetchedAt: number()
|
|
64807
65335
|
});
|
|
@@ -70839,6 +71367,14 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
70839
71367
|
kind: "mutation",
|
|
70840
71368
|
auth: "admin"
|
|
70841
71369
|
});
|
|
71370
|
+
discriminatedUnion("kind", [object({
|
|
71371
|
+
kind: literal("raw"),
|
|
71372
|
+
timings: array(number().int()),
|
|
71373
|
+
settings: TransmitSettingsSchema.optional()
|
|
71374
|
+
}), object({
|
|
71375
|
+
kind: literal("pronto"),
|
|
71376
|
+
code: string()
|
|
71377
|
+
})]);
|
|
70842
71378
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
70843
71379
|
/**
|
|
70844
71380
|
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
@@ -71224,7 +71760,7 @@ function tryConvertUnit(value, from, to) {
|
|
|
71224
71760
|
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
71225
71761
|
}
|
|
71226
71762
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
71227
|
-
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;
|
|
71763
|
+
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.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
71228
71764
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
71229
71765
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
71230
71766
|
new Set(CAP_NAMES);
|
|
@@ -76377,6 +76913,20 @@ Object.freeze({
|
|
|
76377
76913
|
access: "create",
|
|
76378
76914
|
role: "viewer"
|
|
76379
76915
|
},
|
|
76916
|
+
"irTransmitter.getInfo": {
|
|
76917
|
+
capName: "ir-transmitter",
|
|
76918
|
+
capScope: "device",
|
|
76919
|
+
addonId: null,
|
|
76920
|
+
access: "view",
|
|
76921
|
+
role: "viewer"
|
|
76922
|
+
},
|
|
76923
|
+
"irTransmitter.send": {
|
|
76924
|
+
capName: "ir-transmitter",
|
|
76925
|
+
capScope: "device",
|
|
76926
|
+
addonId: null,
|
|
76927
|
+
access: "create",
|
|
76928
|
+
role: "viewer"
|
|
76929
|
+
},
|
|
76380
76930
|
"keychain.delete": {
|
|
76381
76931
|
capName: "keychain",
|
|
76382
76932
|
capScope: "system",
|
|
@@ -77609,6 +78159,13 @@ Object.freeze({
|
|
|
77609
78159
|
access: "create",
|
|
77610
78160
|
role: "admin"
|
|
77611
78161
|
},
|
|
78162
|
+
"nodeRemovalHook.onNodeRemoved": {
|
|
78163
|
+
capName: "node-removal-hook",
|
|
78164
|
+
capScope: "system",
|
|
78165
|
+
addonId: null,
|
|
78166
|
+
access: "create",
|
|
78167
|
+
role: "admin"
|
|
78168
|
+
},
|
|
77612
78169
|
"nodes.clusterAddonStatus": {
|
|
77613
78170
|
capName: "nodes",
|
|
77614
78171
|
capScope: "system",
|
|
@@ -80500,6 +81057,41 @@ Object.freeze({
|
|
|
80500
81057
|
access: "create",
|
|
80501
81058
|
role: "admin"
|
|
80502
81059
|
},
|
|
81060
|
+
"remote.getConfig": {
|
|
81061
|
+
capName: "remote",
|
|
81062
|
+
capScope: "system",
|
|
81063
|
+
addonId: null,
|
|
81064
|
+
access: "view",
|
|
81065
|
+
role: "admin"
|
|
81066
|
+
},
|
|
81067
|
+
"remote.listCommands": {
|
|
81068
|
+
capName: "remote",
|
|
81069
|
+
capScope: "system",
|
|
81070
|
+
addonId: null,
|
|
81071
|
+
access: "view",
|
|
81072
|
+
role: "admin"
|
|
81073
|
+
},
|
|
81074
|
+
"remote.sendCommand": {
|
|
81075
|
+
capName: "remote",
|
|
81076
|
+
capScope: "system",
|
|
81077
|
+
addonId: null,
|
|
81078
|
+
access: "create",
|
|
81079
|
+
role: "admin"
|
|
81080
|
+
},
|
|
81081
|
+
"remote.sendMediaCommand": {
|
|
81082
|
+
capName: "remote",
|
|
81083
|
+
capScope: "system",
|
|
81084
|
+
addonId: null,
|
|
81085
|
+
access: "create",
|
|
81086
|
+
role: "admin"
|
|
81087
|
+
},
|
|
81088
|
+
"remote.setConfig": {
|
|
81089
|
+
capName: "remote",
|
|
81090
|
+
capScope: "system",
|
|
81091
|
+
addonId: null,
|
|
81092
|
+
access: "create",
|
|
81093
|
+
role: "admin"
|
|
81094
|
+
},
|
|
80503
81095
|
"runningState.getStatus": {
|
|
80504
81096
|
capName: "running-state",
|
|
80505
81097
|
capScope: "device",
|
|
@@ -81690,6 +82282,41 @@ Object.freeze({
|
|
|
81690
82282
|
access: "view",
|
|
81691
82283
|
role: "viewer"
|
|
81692
82284
|
},
|
|
82285
|
+
"template.create": {
|
|
82286
|
+
capName: "template",
|
|
82287
|
+
capScope: "system",
|
|
82288
|
+
addonId: null,
|
|
82289
|
+
access: "create",
|
|
82290
|
+
role: "admin"
|
|
82291
|
+
},
|
|
82292
|
+
"template.delete": {
|
|
82293
|
+
capName: "template",
|
|
82294
|
+
capScope: "system",
|
|
82295
|
+
addonId: null,
|
|
82296
|
+
access: "delete",
|
|
82297
|
+
role: "admin"
|
|
82298
|
+
},
|
|
82299
|
+
"template.get": {
|
|
82300
|
+
capName: "template",
|
|
82301
|
+
capScope: "system",
|
|
82302
|
+
addonId: null,
|
|
82303
|
+
access: "view",
|
|
82304
|
+
role: "admin"
|
|
82305
|
+
},
|
|
82306
|
+
"template.list": {
|
|
82307
|
+
capName: "template",
|
|
82308
|
+
capScope: "system",
|
|
82309
|
+
addonId: null,
|
|
82310
|
+
access: "view",
|
|
82311
|
+
role: "admin"
|
|
82312
|
+
},
|
|
82313
|
+
"template.update": {
|
|
82314
|
+
capName: "template",
|
|
82315
|
+
capScope: "system",
|
|
82316
|
+
addonId: null,
|
|
82317
|
+
access: "create",
|
|
82318
|
+
role: "admin"
|
|
82319
|
+
},
|
|
81693
82320
|
"terminalSession.adoptLegacyMonitor": {
|
|
81694
82321
|
capName: "terminal-session",
|
|
81695
82322
|
capScope: "system",
|
|
@@ -84000,6 +84627,11 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
84000
84627
|
icon: "circle-dot"
|
|
84001
84628
|
}]
|
|
84002
84629
|
},
|
|
84630
|
+
"ir-transmitter": {
|
|
84631
|
+
scope: "device",
|
|
84632
|
+
noun: t("IR / RF transmitter", "Trasmettitore IR / RF"),
|
|
84633
|
+
notOperatorFacing: { send: "a raw pulse train is not something an operator composes in an automation; the remote that owns the command table sends it" }
|
|
84634
|
+
},
|
|
84003
84635
|
control: {
|
|
84004
84636
|
scope: "device",
|
|
84005
84637
|
noun: t("Control", "Controllo"),
|
|
@@ -86477,6 +87109,7 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
86477
87109
|
"device-manager": system("the device registry itself — rename, move and remove are administration"),
|
|
86478
87110
|
"device-provider": system(INTERNAL),
|
|
86479
87111
|
"device-removal-hook": system(INTERNAL),
|
|
87112
|
+
"node-removal-hook": system(INTERNAL),
|
|
86480
87113
|
"device-state": system("the runtime-state mirror every trigger already reads through"),
|
|
86481
87114
|
"display-palette": system("the cluster display palette — one colour table for every client, not a device action"),
|
|
86482
87115
|
"embedding-encoder": system(ML),
|
|
@@ -86516,6 +87149,7 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
86516
87149
|
"recording-archive": system(STORAGE),
|
|
86517
87150
|
"recording-export": system("recording exports — requested from the timeline, not an automation step"),
|
|
86518
87151
|
records: system(INTERNAL),
|
|
87152
|
+
remote: system("the per-device remote setup — authored in the Customize remote editor, sent through the remote UI"),
|
|
86519
87153
|
"server-management": system(CLUSTER),
|
|
86520
87154
|
"settings-store": system(INTERNAL),
|
|
86521
87155
|
"smtp-provider": system(INTERNAL),
|
|
@@ -86528,6 +87162,7 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
86528
87162
|
"storage-provider": system(STORAGE),
|
|
86529
87163
|
"stream-broker": system(PIPELINE),
|
|
86530
87164
|
system: system(CLUSTER),
|
|
87165
|
+
template: system("operator-authored templates — edited in their own editor, never actuated"),
|
|
86531
87166
|
"terminal-session": system(CLUSTER),
|
|
86532
87167
|
toast: system(UI_PLUMBING),
|
|
86533
87168
|
training: system(ML),
|
|
@@ -87719,6 +88354,16 @@ Object.freeze({
|
|
|
87719
88354
|
form: "single",
|
|
87720
88355
|
optional: false
|
|
87721
88356
|
}],
|
|
88357
|
+
"irTransmitter.getInfo": [{
|
|
88358
|
+
name: "deviceId",
|
|
88359
|
+
form: "single",
|
|
88360
|
+
optional: false
|
|
88361
|
+
}],
|
|
88362
|
+
"irTransmitter.send": [{
|
|
88363
|
+
name: "deviceId",
|
|
88364
|
+
form: "single",
|
|
88365
|
+
optional: false
|
|
88366
|
+
}],
|
|
87722
88367
|
"keychain.deleteDeviceScope": [{
|
|
87723
88368
|
name: "deviceId",
|
|
87724
88369
|
form: "single",
|
|
@@ -88944,6 +89589,31 @@ Object.freeze({
|
|
|
88944
89589
|
form: "single",
|
|
88945
89590
|
optional: true
|
|
88946
89591
|
}],
|
|
89592
|
+
"remote.getConfig": [{
|
|
89593
|
+
name: "deviceId",
|
|
89594
|
+
form: "single",
|
|
89595
|
+
optional: false
|
|
89596
|
+
}],
|
|
89597
|
+
"remote.listCommands": [{
|
|
89598
|
+
name: "deviceId",
|
|
89599
|
+
form: "single",
|
|
89600
|
+
optional: false
|
|
89601
|
+
}],
|
|
89602
|
+
"remote.sendCommand": [{
|
|
89603
|
+
name: "deviceId",
|
|
89604
|
+
form: "single",
|
|
89605
|
+
optional: false
|
|
89606
|
+
}],
|
|
89607
|
+
"remote.sendMediaCommand": [{
|
|
89608
|
+
name: "deviceId",
|
|
89609
|
+
form: "single",
|
|
89610
|
+
optional: false
|
|
89611
|
+
}],
|
|
89612
|
+
"remote.setConfig": [{
|
|
89613
|
+
name: "deviceId",
|
|
89614
|
+
form: "single",
|
|
89615
|
+
optional: false
|
|
89616
|
+
}],
|
|
88947
89617
|
"runningState.getStatus": [{
|
|
88948
89618
|
name: "deviceId",
|
|
88949
89619
|
form: "single",
|
|
@@ -90894,6 +91564,14 @@ function bestLocationMatch(externalName, existing, threshold = .8) {
|
|
|
90894
91564
|
String.raw`(?<=^|["'(\s>,\[{])`;
|
|
90895
91565
|
var MB = 1024 * 1024;
|
|
90896
91566
|
1024 * MB, 3072 * MB;
|
|
91567
|
+
object({
|
|
91568
|
+
manufacturer: string().optional(),
|
|
91569
|
+
supportedModels: array(string()).optional(),
|
|
91570
|
+
supportedController: string().optional(),
|
|
91571
|
+
commandsEncoding: string(),
|
|
91572
|
+
delay: number().nonnegative().optional(),
|
|
91573
|
+
commands: record(string(), unknown())
|
|
91574
|
+
});
|
|
90897
91575
|
//#endregion
|
|
90898
91576
|
//#region src/callback-host.ts
|
|
90899
91577
|
/**
|
|
@@ -115657,6 +116335,14 @@ var HmChildDevice = class extends BaseDevice {
|
|
|
115657
116335
|
this.valueChangedUnsub = facade.on("valueChanged", (event) => {
|
|
115658
116336
|
if (event.device !== this.address) return;
|
|
115659
116337
|
if (!this.ownsEventChannel(event)) return;
|
|
116338
|
+
this.ctx.logger.debug("Homematic value change accepted", {
|
|
116339
|
+
tags: { deviceId: this.ctx.id },
|
|
116340
|
+
meta: {
|
|
116341
|
+
address: this.address,
|
|
116342
|
+
channel: event.channel,
|
|
116343
|
+
parameter: event.parameter
|
|
116344
|
+
}
|
|
116345
|
+
});
|
|
115660
116346
|
handle(event, "live");
|
|
115661
116347
|
});
|
|
115662
116348
|
this.seedTriggerUnsubs = [facade.on("ready", () => this.seedCurrentValues()), facade.on("connection", () => this.seedCurrentValues())];
|
|
@@ -115731,13 +116417,33 @@ var HmChildDevice = class extends BaseDevice {
|
|
|
115731
116417
|
if (status.includes(event.channel)) return true;
|
|
115732
116418
|
return this.resolveHmDevice()?.channels.some((c) => status.includes(c.address) && (c.dataPoints ?? []).some((d) => d.parameter === event.parameter)) !== true;
|
|
115733
116419
|
}
|
|
116420
|
+
/** A value change the filter refused — named, per reason, on the record. */
|
|
116421
|
+
logValueDropped(event, reason) {
|
|
116422
|
+
this.ctx.logger.debug("Homematic value change dropped", {
|
|
116423
|
+
tags: { deviceId: this.ctx.id },
|
|
116424
|
+
meta: {
|
|
116425
|
+
address: this.address,
|
|
116426
|
+
ownedChannel: this.channel,
|
|
116427
|
+
channel: event.channel,
|
|
116428
|
+
parameter: event.parameter,
|
|
116429
|
+
reason
|
|
116430
|
+
}
|
|
116431
|
+
});
|
|
116432
|
+
}
|
|
115734
116433
|
ownsEventChannel(event) {
|
|
115735
116434
|
const owned = this.channel;
|
|
115736
116435
|
if (owned === void 0) return true;
|
|
115737
116436
|
const channel = event.channel;
|
|
115738
116437
|
if (typeof channel === "string" && channel.length > 0) {
|
|
115739
|
-
if (!this.ownedChannels().includes(channel))
|
|
115740
|
-
|
|
116438
|
+
if (!this.ownedChannels().includes(channel)) {
|
|
116439
|
+
this.logValueDropped(event, "foreign-channel");
|
|
116440
|
+
return false;
|
|
116441
|
+
}
|
|
116442
|
+
if (!this.isPreferredSource(event)) {
|
|
116443
|
+
this.logValueDropped(event, "not-status-source");
|
|
116444
|
+
return false;
|
|
116445
|
+
}
|
|
116446
|
+
return true;
|
|
115741
116447
|
}
|
|
115742
116448
|
this.ctx.logger.warn("Homematic value event without a channel — dropped", {
|
|
115743
116449
|
tags: { deviceId: this.ctx.id },
|