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