@camstack/addon-provider-homeassistant 1.2.155 → 1.2.156
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon.js +6 -1
- package/dist/addon.mjs +6 -1
- package/dist/{dist-CERTsNmo.js → dist-CUS3XDdU.js} +94 -3
- package/dist/{dist-DqKiElqb.mjs → dist-CbGUsakM.mjs} +94 -3
- package/dist/ha-export/ha-export.addon.js +110 -4
- package/dist/ha-export/ha-export.addon.mjs +110 -4
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_dist = require("./dist-
|
|
2
|
+
const require_dist = require("./dist-CUS3XDdU.js");
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
let node_zlib = require("node:zlib");
|
|
5
5
|
//#region src/ha-admin-link.ts
|
|
@@ -7047,6 +7047,11 @@ function createHaNotificationOutputProvider(deps) {
|
|
|
7047
7047
|
}
|
|
7048
7048
|
return out;
|
|
7049
7049
|
},
|
|
7050
|
+
probeTargetConfig: async ({ kind }) => ({
|
|
7051
|
+
ok: false,
|
|
7052
|
+
resolvedUrl: "",
|
|
7053
|
+
error: `Kind '${kind}' does not support credential probing`
|
|
7054
|
+
}),
|
|
7050
7055
|
send: async ({ targetId, notification }) => {
|
|
7051
7056
|
const target = await store.getById(targetId);
|
|
7052
7057
|
if (!target) return {
|
package/dist/addon.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as connectivityCapability, At as string, B as floodCapability, C as buildAddonRouteProvider, Ct as _enum, D as carbonMonoxideCapability, Dt as number, E as calendarSourceCapability, Et as literal, F as deviceAdoptionCapability, G as lawnMowerControlCapability, H as humidifierCapability, J as motionCapability, K as lockControlCapability, L as enumSensorCapability, M as controlCapability, Mt as unknown, N as coverCapability, Nt as url, O as climateControlCapability, Ot as object, P as deviceAdminLinkCapability, Pt as EventCategory, Q as numericSensorCapability, R as eventEmitterCapability, S as brokerCapability, T as buttonCapability, Tt as discriminatedUnion, U as humiditySensorCapability, V as gasCapability, W as imageCapability, X as notificationOutputCapability, Y as normalizeUnit, Z as notifierCapability, _ as automationControlCapability, _t as DeviceRole, at as scriptRunnerCapability, b as binaryCapability, ct as tamperCapability, d as TargetSchema, dt as vacuumControlCapability, et as parseAdminBase, f as accessoriesCapability, ft as valveCapability, g as ambientLightSensorCapability, gt as DeviceFeature, h as alarmPanelCapability, ht as weatherCapability, it as pressureSensorCapability, j as contactCapability, jt as union, k as colorCapability, kt as record, lt as temperatureSensorCapability, m as airQualitySensorCapability, mt as waterHeaterCapability, n as BaseDevice, nt as prepareNotification, ot as smokeCapability, p as addonRoutesCapability, pt as vibrationCapability, q as mediaPlayerCapability, r as BaseDeviceProvider, rt as presenceCapability, s as EnumSensorDateTimeFormatSchema, st as switchCapability, tt as powerMeterCapability, ut as updateCapability, v as batteryCapability, vt as DeviceType, w as buildDeviceAdminUrl, wt as array, x as brightnessCapability, xt as createEvent, y as bestLocationMatch, yt as errMsg, z as fanControlCapability } from "./dist-
|
|
1
|
+
import { A as connectivityCapability, At as string, B as floodCapability, C as buildAddonRouteProvider, Ct as _enum, D as carbonMonoxideCapability, Dt as number, E as calendarSourceCapability, Et as literal, F as deviceAdoptionCapability, G as lawnMowerControlCapability, H as humidifierCapability, J as motionCapability, K as lockControlCapability, L as enumSensorCapability, M as controlCapability, Mt as unknown, N as coverCapability, Nt as url, O as climateControlCapability, Ot as object, P as deviceAdminLinkCapability, Pt as EventCategory, Q as numericSensorCapability, R as eventEmitterCapability, S as brokerCapability, T as buttonCapability, Tt as discriminatedUnion, U as humiditySensorCapability, V as gasCapability, W as imageCapability, X as notificationOutputCapability, Y as normalizeUnit, Z as notifierCapability, _ as automationControlCapability, _t as DeviceRole, at as scriptRunnerCapability, b as binaryCapability, ct as tamperCapability, d as TargetSchema, dt as vacuumControlCapability, et as parseAdminBase, f as accessoriesCapability, ft as valveCapability, g as ambientLightSensorCapability, gt as DeviceFeature, h as alarmPanelCapability, ht as weatherCapability, it as pressureSensorCapability, j as contactCapability, jt as union, k as colorCapability, kt as record, lt as temperatureSensorCapability, m as airQualitySensorCapability, mt as waterHeaterCapability, n as BaseDevice, nt as prepareNotification, ot as smokeCapability, p as addonRoutesCapability, pt as vibrationCapability, q as mediaPlayerCapability, r as BaseDeviceProvider, rt as presenceCapability, s as EnumSensorDateTimeFormatSchema, st as switchCapability, tt as powerMeterCapability, ut as updateCapability, v as batteryCapability, vt as DeviceType, w as buildDeviceAdminUrl, wt as array, x as brightnessCapability, xt as createEvent, y as bestLocationMatch, yt as errMsg, z as fanControlCapability } from "./dist-CbGUsakM.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
|
|
4
4
|
//#region src/ha-admin-link.ts
|
|
@@ -7046,6 +7046,11 @@ function createHaNotificationOutputProvider(deps) {
|
|
|
7046
7046
|
}
|
|
7047
7047
|
return out;
|
|
7048
7048
|
},
|
|
7049
|
+
probeTargetConfig: async ({ kind }) => ({
|
|
7050
|
+
ok: false,
|
|
7051
|
+
resolvedUrl: "",
|
|
7052
|
+
error: `Kind '${kind}' does not support credential probing`
|
|
7053
|
+
}),
|
|
7049
7054
|
send: async ({ targetId, notification }) => {
|
|
7050
7055
|
const target = await store.getById(targetId);
|
|
7051
7056
|
if (!target) return {
|
|
@@ -5379,7 +5379,7 @@ var ZodIssueCode = {
|
|
|
5379
5379
|
var ZodFirstPartyTypeKind;
|
|
5380
5380
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5381
5381
|
//#endregion
|
|
5382
|
-
//#region ../types/dist/sleep-
|
|
5382
|
+
//#region ../types/dist/sleep-DXKLNFvA.mjs
|
|
5383
5383
|
/**
|
|
5384
5384
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5385
5385
|
* window to float samples (D455).
|
|
@@ -5687,6 +5687,43 @@ function hydrateField(field, values) {
|
|
|
5687
5687
|
}
|
|
5688
5688
|
const rawValue = storedValue !== void 0 ? storedValue : defaultValue !== void 0 ? defaultValue : null;
|
|
5689
5689
|
const value = field.type === "textarea" && field.isJson && rawValue !== null && typeof rawValue === "object" ? JSON.stringify(rawValue, null, 2) : rawValue;
|
|
5690
|
+
if (field.type === "tags" && typeof field.suggestionsFrom === "string") {
|
|
5691
|
+
const from = values[field.suggestionsFrom];
|
|
5692
|
+
const extra = Array.isArray(from) ? from.filter((s) => typeof s === "string" && s.length > 0) : [];
|
|
5693
|
+
const merged = [...new Set([...field.suggestions ?? [], ...extra])];
|
|
5694
|
+
return {
|
|
5695
|
+
...field,
|
|
5696
|
+
suggestions: merged,
|
|
5697
|
+
value
|
|
5698
|
+
};
|
|
5699
|
+
}
|
|
5700
|
+
if ((field.type === "select" || field.type === "multiselect") && typeof field.optionsFrom === "string") {
|
|
5701
|
+
const from = values[field.optionsFrom];
|
|
5702
|
+
const byValue = /* @__PURE__ */ new Map();
|
|
5703
|
+
for (const opt of field.options) byValue.set(opt.value, opt);
|
|
5704
|
+
if (Array.isArray(from)) for (const entry of from) {
|
|
5705
|
+
if (typeof entry === "string" && entry.length > 0) {
|
|
5706
|
+
if (!byValue.has(entry)) byValue.set(entry, {
|
|
5707
|
+
value: entry,
|
|
5708
|
+
label: entry
|
|
5709
|
+
});
|
|
5710
|
+
continue;
|
|
5711
|
+
}
|
|
5712
|
+
if (entry === null || typeof entry !== "object") continue;
|
|
5713
|
+
const v = Reflect.get(entry, "value");
|
|
5714
|
+
const lbl = Reflect.get(entry, "label");
|
|
5715
|
+
if (typeof v !== "string" || v.length === 0) continue;
|
|
5716
|
+
if (!byValue.has(v)) byValue.set(v, {
|
|
5717
|
+
value: v,
|
|
5718
|
+
label: typeof lbl === "string" && lbl.length > 0 ? lbl : v
|
|
5719
|
+
});
|
|
5720
|
+
}
|
|
5721
|
+
return {
|
|
5722
|
+
...field,
|
|
5723
|
+
options: [...byValue.values()],
|
|
5724
|
+
value
|
|
5725
|
+
};
|
|
5726
|
+
}
|
|
5690
5727
|
return {
|
|
5691
5728
|
...field,
|
|
5692
5729
|
value
|
|
@@ -18329,6 +18366,17 @@ var SendResultSchema = object({
|
|
|
18329
18366
|
});
|
|
18330
18367
|
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
18331
18368
|
var TestResultSchema = SendResultSchema;
|
|
18369
|
+
/**
|
|
18370
|
+
* Pre-save credential probe against a partial (unsaved) target config.
|
|
18371
|
+
* `resolvedUrl` never includes secrets (token stripped from path).
|
|
18372
|
+
*/
|
|
18373
|
+
var ProbeTargetConfigResultSchema = object({
|
|
18374
|
+
ok: boolean(),
|
|
18375
|
+
resolvedUrl: string(),
|
|
18376
|
+
httpStatus: number().int().optional(),
|
|
18377
|
+
stateInstance: string().optional(),
|
|
18378
|
+
error: string().optional()
|
|
18379
|
+
});
|
|
18332
18380
|
var notificationOutputCapability = {
|
|
18333
18381
|
name: "notification-output",
|
|
18334
18382
|
scope: "system",
|
|
@@ -18336,10 +18384,32 @@ var notificationOutputCapability = {
|
|
|
18336
18384
|
methods: {
|
|
18337
18385
|
listTargetKinds: method(object({}), array(TargetKindSchema)),
|
|
18338
18386
|
listTargets: method(object({}), array(TargetSchema), { auth: "admin" }),
|
|
18387
|
+
/**
|
|
18388
|
+
* One target WITH secrets — admin edit / duplicate hydration only.
|
|
18389
|
+
* `listTargets` stays redacted; the editor loads this so password fields
|
|
18390
|
+
* are filled (masked in the input) and a save can round-trip the token
|
|
18391
|
+
* when a destination changes (Duplicate with a new chatId, etc.).
|
|
18392
|
+
*/
|
|
18393
|
+
getTarget: method(object({ targetId: string() }), TargetSchema, { auth: "admin" }),
|
|
18339
18394
|
discoverTargets: method(object({
|
|
18340
18395
|
kind: string(),
|
|
18341
|
-
config: record(string(), unknown()).optional()
|
|
18396
|
+
config: record(string(), unknown()).optional(),
|
|
18397
|
+
/**
|
|
18398
|
+
* When editing / duplicating, the blank password field never round-trips
|
|
18399
|
+
* the stored token. Pass the source target id so the provider can restore
|
|
18400
|
+
* secrets server-side before dialling (same merge as upsert).
|
|
18401
|
+
*/
|
|
18402
|
+
targetId: string().optional()
|
|
18342
18403
|
}), array(DiscoveredTargetSchema), { auth: "admin" }),
|
|
18404
|
+
probeTargetConfig: method(object({
|
|
18405
|
+
kind: string(),
|
|
18406
|
+
config: record(string(), unknown()),
|
|
18407
|
+
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
18408
|
+
targetId: string().optional()
|
|
18409
|
+
}), ProbeTargetConfigResultSchema, {
|
|
18410
|
+
kind: "mutation",
|
|
18411
|
+
auth: "admin"
|
|
18412
|
+
}),
|
|
18343
18413
|
send: method(object({
|
|
18344
18414
|
targetId: string(),
|
|
18345
18415
|
notification: NotificationSchema
|
|
@@ -18354,7 +18424,16 @@ var notificationOutputCapability = {
|
|
|
18354
18424
|
kind: "mutation",
|
|
18355
18425
|
auth: "admin"
|
|
18356
18426
|
}),
|
|
18357
|
-
upsertTarget: method(object({
|
|
18427
|
+
upsertTarget: method(object({
|
|
18428
|
+
target: TargetSchema,
|
|
18429
|
+
/**
|
|
18430
|
+
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
18431
|
+
* existing row. The UI never holds the stored token; blank / redacted
|
|
18432
|
+
* password fields are restored from this source (D634 still applies if
|
|
18433
|
+
* destinations diverge without a re-typed secret).
|
|
18434
|
+
*/
|
|
18435
|
+
cloneSecretsFrom: string().optional()
|
|
18436
|
+
}), TargetSchema, {
|
|
18358
18437
|
kind: "mutation",
|
|
18359
18438
|
auth: "admin"
|
|
18360
18439
|
}),
|
|
@@ -44767,6 +44846,12 @@ Object.freeze({
|
|
|
44767
44846
|
addonId: null,
|
|
44768
44847
|
access: "view"
|
|
44769
44848
|
},
|
|
44849
|
+
"notificationOutput.getTarget": {
|
|
44850
|
+
capName: "notification-output",
|
|
44851
|
+
capScope: "system",
|
|
44852
|
+
addonId: null,
|
|
44853
|
+
access: "view"
|
|
44854
|
+
},
|
|
44770
44855
|
"notificationOutput.listTargetKinds": {
|
|
44771
44856
|
capName: "notification-output",
|
|
44772
44857
|
capScope: "system",
|
|
@@ -44779,6 +44864,12 @@ Object.freeze({
|
|
|
44779
44864
|
addonId: null,
|
|
44780
44865
|
access: "view"
|
|
44781
44866
|
},
|
|
44867
|
+
"notificationOutput.probeTargetConfig": {
|
|
44868
|
+
capName: "notification-output",
|
|
44869
|
+
capScope: "system",
|
|
44870
|
+
addonId: null,
|
|
44871
|
+
access: "create"
|
|
44872
|
+
},
|
|
44782
44873
|
"notificationOutput.send": {
|
|
44783
44874
|
capName: "notification-output",
|
|
44784
44875
|
capScope: "system",
|
|
@@ -5378,7 +5378,7 @@ var ZodIssueCode = {
|
|
|
5378
5378
|
var ZodFirstPartyTypeKind;
|
|
5379
5379
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5380
5380
|
//#endregion
|
|
5381
|
-
//#region ../types/dist/sleep-
|
|
5381
|
+
//#region ../types/dist/sleep-DXKLNFvA.mjs
|
|
5382
5382
|
/**
|
|
5383
5383
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5384
5384
|
* window to float samples (D455).
|
|
@@ -5686,6 +5686,43 @@ function hydrateField(field, values) {
|
|
|
5686
5686
|
}
|
|
5687
5687
|
const rawValue = storedValue !== void 0 ? storedValue : defaultValue !== void 0 ? defaultValue : null;
|
|
5688
5688
|
const value = field.type === "textarea" && field.isJson && rawValue !== null && typeof rawValue === "object" ? JSON.stringify(rawValue, null, 2) : rawValue;
|
|
5689
|
+
if (field.type === "tags" && typeof field.suggestionsFrom === "string") {
|
|
5690
|
+
const from = values[field.suggestionsFrom];
|
|
5691
|
+
const extra = Array.isArray(from) ? from.filter((s) => typeof s === "string" && s.length > 0) : [];
|
|
5692
|
+
const merged = [...new Set([...field.suggestions ?? [], ...extra])];
|
|
5693
|
+
return {
|
|
5694
|
+
...field,
|
|
5695
|
+
suggestions: merged,
|
|
5696
|
+
value
|
|
5697
|
+
};
|
|
5698
|
+
}
|
|
5699
|
+
if ((field.type === "select" || field.type === "multiselect") && typeof field.optionsFrom === "string") {
|
|
5700
|
+
const from = values[field.optionsFrom];
|
|
5701
|
+
const byValue = /* @__PURE__ */ new Map();
|
|
5702
|
+
for (const opt of field.options) byValue.set(opt.value, opt);
|
|
5703
|
+
if (Array.isArray(from)) for (const entry of from) {
|
|
5704
|
+
if (typeof entry === "string" && entry.length > 0) {
|
|
5705
|
+
if (!byValue.has(entry)) byValue.set(entry, {
|
|
5706
|
+
value: entry,
|
|
5707
|
+
label: entry
|
|
5708
|
+
});
|
|
5709
|
+
continue;
|
|
5710
|
+
}
|
|
5711
|
+
if (entry === null || typeof entry !== "object") continue;
|
|
5712
|
+
const v = Reflect.get(entry, "value");
|
|
5713
|
+
const lbl = Reflect.get(entry, "label");
|
|
5714
|
+
if (typeof v !== "string" || v.length === 0) continue;
|
|
5715
|
+
if (!byValue.has(v)) byValue.set(v, {
|
|
5716
|
+
value: v,
|
|
5717
|
+
label: typeof lbl === "string" && lbl.length > 0 ? lbl : v
|
|
5718
|
+
});
|
|
5719
|
+
}
|
|
5720
|
+
return {
|
|
5721
|
+
...field,
|
|
5722
|
+
options: [...byValue.values()],
|
|
5723
|
+
value
|
|
5724
|
+
};
|
|
5725
|
+
}
|
|
5689
5726
|
return {
|
|
5690
5727
|
...field,
|
|
5691
5728
|
value
|
|
@@ -18328,6 +18365,17 @@ var SendResultSchema = object({
|
|
|
18328
18365
|
});
|
|
18329
18366
|
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
18330
18367
|
var TestResultSchema = SendResultSchema;
|
|
18368
|
+
/**
|
|
18369
|
+
* Pre-save credential probe against a partial (unsaved) target config.
|
|
18370
|
+
* `resolvedUrl` never includes secrets (token stripped from path).
|
|
18371
|
+
*/
|
|
18372
|
+
var ProbeTargetConfigResultSchema = object({
|
|
18373
|
+
ok: boolean(),
|
|
18374
|
+
resolvedUrl: string(),
|
|
18375
|
+
httpStatus: number().int().optional(),
|
|
18376
|
+
stateInstance: string().optional(),
|
|
18377
|
+
error: string().optional()
|
|
18378
|
+
});
|
|
18331
18379
|
var notificationOutputCapability = {
|
|
18332
18380
|
name: "notification-output",
|
|
18333
18381
|
scope: "system",
|
|
@@ -18335,10 +18383,32 @@ var notificationOutputCapability = {
|
|
|
18335
18383
|
methods: {
|
|
18336
18384
|
listTargetKinds: method(object({}), array(TargetKindSchema)),
|
|
18337
18385
|
listTargets: method(object({}), array(TargetSchema), { auth: "admin" }),
|
|
18386
|
+
/**
|
|
18387
|
+
* One target WITH secrets — admin edit / duplicate hydration only.
|
|
18388
|
+
* `listTargets` stays redacted; the editor loads this so password fields
|
|
18389
|
+
* are filled (masked in the input) and a save can round-trip the token
|
|
18390
|
+
* when a destination changes (Duplicate with a new chatId, etc.).
|
|
18391
|
+
*/
|
|
18392
|
+
getTarget: method(object({ targetId: string() }), TargetSchema, { auth: "admin" }),
|
|
18338
18393
|
discoverTargets: method(object({
|
|
18339
18394
|
kind: string(),
|
|
18340
|
-
config: record(string(), unknown()).optional()
|
|
18395
|
+
config: record(string(), unknown()).optional(),
|
|
18396
|
+
/**
|
|
18397
|
+
* When editing / duplicating, the blank password field never round-trips
|
|
18398
|
+
* the stored token. Pass the source target id so the provider can restore
|
|
18399
|
+
* secrets server-side before dialling (same merge as upsert).
|
|
18400
|
+
*/
|
|
18401
|
+
targetId: string().optional()
|
|
18341
18402
|
}), array(DiscoveredTargetSchema), { auth: "admin" }),
|
|
18403
|
+
probeTargetConfig: method(object({
|
|
18404
|
+
kind: string(),
|
|
18405
|
+
config: record(string(), unknown()),
|
|
18406
|
+
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
18407
|
+
targetId: string().optional()
|
|
18408
|
+
}), ProbeTargetConfigResultSchema, {
|
|
18409
|
+
kind: "mutation",
|
|
18410
|
+
auth: "admin"
|
|
18411
|
+
}),
|
|
18342
18412
|
send: method(object({
|
|
18343
18413
|
targetId: string(),
|
|
18344
18414
|
notification: NotificationSchema
|
|
@@ -18353,7 +18423,16 @@ var notificationOutputCapability = {
|
|
|
18353
18423
|
kind: "mutation",
|
|
18354
18424
|
auth: "admin"
|
|
18355
18425
|
}),
|
|
18356
|
-
upsertTarget: method(object({
|
|
18426
|
+
upsertTarget: method(object({
|
|
18427
|
+
target: TargetSchema,
|
|
18428
|
+
/**
|
|
18429
|
+
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
18430
|
+
* existing row. The UI never holds the stored token; blank / redacted
|
|
18431
|
+
* password fields are restored from this source (D634 still applies if
|
|
18432
|
+
* destinations diverge without a re-typed secret).
|
|
18433
|
+
*/
|
|
18434
|
+
cloneSecretsFrom: string().optional()
|
|
18435
|
+
}), TargetSchema, {
|
|
18357
18436
|
kind: "mutation",
|
|
18358
18437
|
auth: "admin"
|
|
18359
18438
|
}),
|
|
@@ -44766,6 +44845,12 @@ Object.freeze({
|
|
|
44766
44845
|
addonId: null,
|
|
44767
44846
|
access: "view"
|
|
44768
44847
|
},
|
|
44848
|
+
"notificationOutput.getTarget": {
|
|
44849
|
+
capName: "notification-output",
|
|
44850
|
+
capScope: "system",
|
|
44851
|
+
addonId: null,
|
|
44852
|
+
access: "view"
|
|
44853
|
+
},
|
|
44769
44854
|
"notificationOutput.listTargetKinds": {
|
|
44770
44855
|
capName: "notification-output",
|
|
44771
44856
|
capScope: "system",
|
|
@@ -44778,6 +44863,12 @@ Object.freeze({
|
|
|
44778
44863
|
addonId: null,
|
|
44779
44864
|
access: "view"
|
|
44780
44865
|
},
|
|
44866
|
+
"notificationOutput.probeTargetConfig": {
|
|
44867
|
+
capName: "notification-output",
|
|
44868
|
+
capScope: "system",
|
|
44869
|
+
addonId: null,
|
|
44870
|
+
access: "create"
|
|
44871
|
+
},
|
|
44781
44872
|
"notificationOutput.send": {
|
|
44782
44873
|
capName: "notification-output",
|
|
44783
44874
|
capScope: "system",
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
//#endregion
|
|
6
|
-
const require_dist = require("../dist-
|
|
6
|
+
const require_dist = require("../dist-CUS3XDdU.js");
|
|
7
7
|
let node_crypto = require("node:crypto");
|
|
8
8
|
//#region src/ha-export/topics.ts
|
|
9
9
|
/**
|
|
@@ -2582,13 +2582,18 @@ mireds: {
|
|
|
2582
2582
|
},
|
|
2583
2583
|
/**
|
|
2584
2584
|
* The generic user-settable input. `value` is `number | string` and
|
|
2585
|
-
* `kind` says which of the four shapes it is
|
|
2586
|
-
*
|
|
2587
|
-
* the
|
|
2585
|
+
* `kind` on the slice says which of the four shapes it is. The row
|
|
2586
|
+
* here is the PROJECTOR + route authority (`writable` gates
|
|
2587
|
+
* `control.setValue`); the announced platform (`select` / `number` /
|
|
2588
|
+
* read-only `sensor`) is minted at reconcile from the slice by
|
|
2589
|
+
* {@link controlEntitySpecs} — a static `select` here cannot carry
|
|
2590
|
+
* the device's live `options`, and a static `number` cannot carry
|
|
2591
|
+
* its live min/max/step.
|
|
2588
2592
|
*/
|
|
2589
2593
|
control: {
|
|
2590
2594
|
platform: "sensor",
|
|
2591
2595
|
field: "value",
|
|
2596
|
+
writable: true,
|
|
2592
2597
|
extras: { kind: {
|
|
2593
2598
|
platform: "sensor",
|
|
2594
2599
|
field: "kind",
|
|
@@ -2755,6 +2760,71 @@ function capEntitySpecs(capName) {
|
|
|
2755
2760
|
});
|
|
2756
2761
|
return specs;
|
|
2757
2762
|
}
|
|
2763
|
+
function readControlOptions(slice) {
|
|
2764
|
+
const raw = slice?.["options"];
|
|
2765
|
+
if (!Array.isArray(raw)) return [];
|
|
2766
|
+
return raw.filter((entry) => typeof entry === "string" && entry.length > 0);
|
|
2767
|
+
}
|
|
2768
|
+
function readFiniteNumber(slice, field) {
|
|
2769
|
+
const raw = slice?.[field];
|
|
2770
|
+
return typeof raw === "number" && Number.isFinite(raw) ? raw : void 0;
|
|
2771
|
+
}
|
|
2772
|
+
/**
|
|
2773
|
+
* The announced shape of a `control` device, from its live slice.
|
|
2774
|
+
*
|
|
2775
|
+
* `CAP_ENTITY_MAP.control` cannot name a static `select`/`number`: the
|
|
2776
|
+
* options and the bounds live on the slice and change (VPN station list,
|
|
2777
|
+
* HA `input_number` limits). A select with no options is an entity HA
|
|
2778
|
+
* builds with nothing to choose from — so an empty list falls back to a
|
|
2779
|
+
* read-only sensor rather than a dead control.
|
|
2780
|
+
*/
|
|
2781
|
+
function controlEntitySpecs(slice) {
|
|
2782
|
+
const kind = typeof slice?.["kind"] === "string" ? slice["kind"] : null;
|
|
2783
|
+
const primary = derivedEntityId("control");
|
|
2784
|
+
const kindExtra = {
|
|
2785
|
+
entity: derivedExtraEntityId("control", "kind"),
|
|
2786
|
+
platform: "sensor",
|
|
2787
|
+
label: "Input kind",
|
|
2788
|
+
entityCategory: "diagnostic",
|
|
2789
|
+
enabledByDefault: false
|
|
2790
|
+
};
|
|
2791
|
+
if (kind === "select") {
|
|
2792
|
+
const options = readControlOptions(slice);
|
|
2793
|
+
if (options.length > 0) return [{
|
|
2794
|
+
entity: primary,
|
|
2795
|
+
platform: "select",
|
|
2796
|
+
label: humanise("control"),
|
|
2797
|
+
writable: true,
|
|
2798
|
+
options,
|
|
2799
|
+
enabledByDefault: true
|
|
2800
|
+
}, kindExtra];
|
|
2801
|
+
}
|
|
2802
|
+
if (kind === "numeric") {
|
|
2803
|
+
const min = readFiniteNumber(slice, "min") ?? PERCENT_RANGE.min;
|
|
2804
|
+
const max = readFiniteNumber(slice, "max") ?? PERCENT_RANGE.max;
|
|
2805
|
+
const step = readFiniteNumber(slice, "step") ?? PERCENT_RANGE.step;
|
|
2806
|
+
const unit = typeof slice?.["unit"] === "string" ? slice["unit"] : void 0;
|
|
2807
|
+
if (min < max && step > 0) return [{
|
|
2808
|
+
entity: primary,
|
|
2809
|
+
platform: "number",
|
|
2810
|
+
label: humanise("control"),
|
|
2811
|
+
writable: true,
|
|
2812
|
+
range: {
|
|
2813
|
+
min,
|
|
2814
|
+
max,
|
|
2815
|
+
step
|
|
2816
|
+
},
|
|
2817
|
+
...unit !== void 0 ? { unit } : {},
|
|
2818
|
+
enabledByDefault: true
|
|
2819
|
+
}, kindExtra];
|
|
2820
|
+
}
|
|
2821
|
+
return [{
|
|
2822
|
+
entity: primary,
|
|
2823
|
+
platform: "sensor",
|
|
2824
|
+
label: humanise("control"),
|
|
2825
|
+
enabledByDefault: true
|
|
2826
|
+
}, kindExtra];
|
|
2827
|
+
}
|
|
2758
2828
|
var CAPS_NOT_EXPORTED = [
|
|
2759
2829
|
{
|
|
2760
2830
|
cap: "recording-onboard",
|
|
@@ -2984,6 +3054,15 @@ function buildDerivedPlan(device, options = UNNEGOTIATED_PLAN_OPTIONS) {
|
|
|
2984
3054
|
* two halves of this file would build the same entity id twice.
|
|
2985
3055
|
*/
|
|
2986
3056
|
if (CAMERA_DERIVED_CAPS.includes(cap)) continue;
|
|
3057
|
+
/**
|
|
3058
|
+
* `control` is slice-shaped: select options and number bounds are not
|
|
3059
|
+
* on the static row. Mint the announced platform here; the CAP_ENTITY_MAP
|
|
3060
|
+
* row stays the projector + writable-route authority.
|
|
3061
|
+
*/
|
|
3062
|
+
if (cap === "control") {
|
|
3063
|
+
specs.push(...controlEntitySpecs(device.capSlices?.["control"]).map((spec) => degradeUnsupported(spec, options)));
|
|
3064
|
+
continue;
|
|
3065
|
+
}
|
|
2987
3066
|
const mapping = CAP_ENTITY_MAP[cap];
|
|
2988
3067
|
const platform = nativePlatformFor(cap);
|
|
2989
3068
|
const plan = mapping === void 0 || platform === null || !options.platforms.has(platform) ? null : buildNativeComponent({
|
|
@@ -3207,6 +3286,11 @@ var CAP_COMMAND_ROUTES = {
|
|
|
3207
3286
|
deviceId,
|
|
3208
3287
|
capName: "button"
|
|
3209
3288
|
}) },
|
|
3289
|
+
control: { primary: (deviceId, value) => value.trim().length === 0 ? null : {
|
|
3290
|
+
kind: "cap-control",
|
|
3291
|
+
deviceId,
|
|
3292
|
+
value
|
|
3293
|
+
} },
|
|
3210
3294
|
cover: {
|
|
3211
3295
|
extras: {
|
|
3212
3296
|
position: (deviceId, value) => {
|
|
@@ -3895,6 +3979,28 @@ async function applyCapCommand(device, command) {
|
|
|
3895
3979
|
};
|
|
3896
3980
|
await device.button.press({});
|
|
3897
3981
|
return { ok: true };
|
|
3982
|
+
case "cap-control": return call(device.control, "control", async (control) => {
|
|
3983
|
+
const status = await control.getStatus({});
|
|
3984
|
+
if (status === null || typeof status !== "object") throw new Error("the device reports no control status, so setValue has no kind");
|
|
3985
|
+
const kind = Reflect.get(status, "kind");
|
|
3986
|
+
if (kind === "numeric") {
|
|
3987
|
+
const numeric = Number(command.value);
|
|
3988
|
+
if (!Number.isFinite(numeric)) throw new Error(`control value is not a number: ${command.value}`);
|
|
3989
|
+
await control.setValue({ control: {
|
|
3990
|
+
kind: "numeric",
|
|
3991
|
+
value: numeric
|
|
3992
|
+
} });
|
|
3993
|
+
return;
|
|
3994
|
+
}
|
|
3995
|
+
if (kind === "select" || kind === "text" || kind === "datetime") {
|
|
3996
|
+
await control.setValue({ control: {
|
|
3997
|
+
kind,
|
|
3998
|
+
value: command.value
|
|
3999
|
+
} });
|
|
4000
|
+
return;
|
|
4001
|
+
}
|
|
4002
|
+
throw new Error(`unsupported control kind: ${String(kind)}`);
|
|
4003
|
+
});
|
|
3898
4004
|
case "cover-position": return call(device.cover, "cover", (cover) => cover.setPosition({ position: command.position }));
|
|
3899
4005
|
case "cover-tilt": return call(device.cover, "cover", (cover) => cover.setTiltPosition({ tiltPosition: command.tiltPosition }));
|
|
3900
4006
|
case "cover-verb": return call(device.cover, "cover", (cover) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as oauthIntegrationCapability, At as string, C as buildAddonRouteProvider, I as deviceExportCapability, Pt as EventCategory, St as nodePin, a as COCO_TO_MACRO, bt as BaseAddon, c as FanDirectionSchema, i as CAMERA_SWITCH_ORDER, l as HvacModeSchema, o as CameraSwitchIdSchema, p as addonRoutesCapability, t as AlarmArmModeSchema, u as MediaPlayerRepeatSchema } from "../dist-
|
|
1
|
+
import { $ as oauthIntegrationCapability, At as string, C as buildAddonRouteProvider, I as deviceExportCapability, Pt as EventCategory, St as nodePin, a as COCO_TO_MACRO, bt as BaseAddon, c as FanDirectionSchema, i as CAMERA_SWITCH_ORDER, l as HvacModeSchema, o as CameraSwitchIdSchema, p as addonRoutesCapability, t as AlarmArmModeSchema, u as MediaPlayerRepeatSchema } from "../dist-CbGUsakM.mjs";
|
|
2
2
|
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
3
3
|
//#region src/ha-export/topics.ts
|
|
4
4
|
/**
|
|
@@ -2577,13 +2577,18 @@ mireds: {
|
|
|
2577
2577
|
},
|
|
2578
2578
|
/**
|
|
2579
2579
|
* The generic user-settable input. `value` is `number | string` and
|
|
2580
|
-
* `kind` says which of the four shapes it is
|
|
2581
|
-
*
|
|
2582
|
-
* the
|
|
2580
|
+
* `kind` on the slice says which of the four shapes it is. The row
|
|
2581
|
+
* here is the PROJECTOR + route authority (`writable` gates
|
|
2582
|
+
* `control.setValue`); the announced platform (`select` / `number` /
|
|
2583
|
+
* read-only `sensor`) is minted at reconcile from the slice by
|
|
2584
|
+
* {@link controlEntitySpecs} — a static `select` here cannot carry
|
|
2585
|
+
* the device's live `options`, and a static `number` cannot carry
|
|
2586
|
+
* its live min/max/step.
|
|
2583
2587
|
*/
|
|
2584
2588
|
control: {
|
|
2585
2589
|
platform: "sensor",
|
|
2586
2590
|
field: "value",
|
|
2591
|
+
writable: true,
|
|
2587
2592
|
extras: { kind: {
|
|
2588
2593
|
platform: "sensor",
|
|
2589
2594
|
field: "kind",
|
|
@@ -2750,6 +2755,71 @@ function capEntitySpecs(capName) {
|
|
|
2750
2755
|
});
|
|
2751
2756
|
return specs;
|
|
2752
2757
|
}
|
|
2758
|
+
function readControlOptions(slice) {
|
|
2759
|
+
const raw = slice?.["options"];
|
|
2760
|
+
if (!Array.isArray(raw)) return [];
|
|
2761
|
+
return raw.filter((entry) => typeof entry === "string" && entry.length > 0);
|
|
2762
|
+
}
|
|
2763
|
+
function readFiniteNumber(slice, field) {
|
|
2764
|
+
const raw = slice?.[field];
|
|
2765
|
+
return typeof raw === "number" && Number.isFinite(raw) ? raw : void 0;
|
|
2766
|
+
}
|
|
2767
|
+
/**
|
|
2768
|
+
* The announced shape of a `control` device, from its live slice.
|
|
2769
|
+
*
|
|
2770
|
+
* `CAP_ENTITY_MAP.control` cannot name a static `select`/`number`: the
|
|
2771
|
+
* options and the bounds live on the slice and change (VPN station list,
|
|
2772
|
+
* HA `input_number` limits). A select with no options is an entity HA
|
|
2773
|
+
* builds with nothing to choose from — so an empty list falls back to a
|
|
2774
|
+
* read-only sensor rather than a dead control.
|
|
2775
|
+
*/
|
|
2776
|
+
function controlEntitySpecs(slice) {
|
|
2777
|
+
const kind = typeof slice?.["kind"] === "string" ? slice["kind"] : null;
|
|
2778
|
+
const primary = derivedEntityId("control");
|
|
2779
|
+
const kindExtra = {
|
|
2780
|
+
entity: derivedExtraEntityId("control", "kind"),
|
|
2781
|
+
platform: "sensor",
|
|
2782
|
+
label: "Input kind",
|
|
2783
|
+
entityCategory: "diagnostic",
|
|
2784
|
+
enabledByDefault: false
|
|
2785
|
+
};
|
|
2786
|
+
if (kind === "select") {
|
|
2787
|
+
const options = readControlOptions(slice);
|
|
2788
|
+
if (options.length > 0) return [{
|
|
2789
|
+
entity: primary,
|
|
2790
|
+
platform: "select",
|
|
2791
|
+
label: humanise("control"),
|
|
2792
|
+
writable: true,
|
|
2793
|
+
options,
|
|
2794
|
+
enabledByDefault: true
|
|
2795
|
+
}, kindExtra];
|
|
2796
|
+
}
|
|
2797
|
+
if (kind === "numeric") {
|
|
2798
|
+
const min = readFiniteNumber(slice, "min") ?? PERCENT_RANGE.min;
|
|
2799
|
+
const max = readFiniteNumber(slice, "max") ?? PERCENT_RANGE.max;
|
|
2800
|
+
const step = readFiniteNumber(slice, "step") ?? PERCENT_RANGE.step;
|
|
2801
|
+
const unit = typeof slice?.["unit"] === "string" ? slice["unit"] : void 0;
|
|
2802
|
+
if (min < max && step > 0) return [{
|
|
2803
|
+
entity: primary,
|
|
2804
|
+
platform: "number",
|
|
2805
|
+
label: humanise("control"),
|
|
2806
|
+
writable: true,
|
|
2807
|
+
range: {
|
|
2808
|
+
min,
|
|
2809
|
+
max,
|
|
2810
|
+
step
|
|
2811
|
+
},
|
|
2812
|
+
...unit !== void 0 ? { unit } : {},
|
|
2813
|
+
enabledByDefault: true
|
|
2814
|
+
}, kindExtra];
|
|
2815
|
+
}
|
|
2816
|
+
return [{
|
|
2817
|
+
entity: primary,
|
|
2818
|
+
platform: "sensor",
|
|
2819
|
+
label: humanise("control"),
|
|
2820
|
+
enabledByDefault: true
|
|
2821
|
+
}, kindExtra];
|
|
2822
|
+
}
|
|
2753
2823
|
var CAPS_NOT_EXPORTED = [
|
|
2754
2824
|
{
|
|
2755
2825
|
cap: "recording-onboard",
|
|
@@ -2979,6 +3049,15 @@ function buildDerivedPlan(device, options = UNNEGOTIATED_PLAN_OPTIONS) {
|
|
|
2979
3049
|
* two halves of this file would build the same entity id twice.
|
|
2980
3050
|
*/
|
|
2981
3051
|
if (CAMERA_DERIVED_CAPS.includes(cap)) continue;
|
|
3052
|
+
/**
|
|
3053
|
+
* `control` is slice-shaped: select options and number bounds are not
|
|
3054
|
+
* on the static row. Mint the announced platform here; the CAP_ENTITY_MAP
|
|
3055
|
+
* row stays the projector + writable-route authority.
|
|
3056
|
+
*/
|
|
3057
|
+
if (cap === "control") {
|
|
3058
|
+
specs.push(...controlEntitySpecs(device.capSlices?.["control"]).map((spec) => degradeUnsupported(spec, options)));
|
|
3059
|
+
continue;
|
|
3060
|
+
}
|
|
2982
3061
|
const mapping = CAP_ENTITY_MAP[cap];
|
|
2983
3062
|
const platform = nativePlatformFor(cap);
|
|
2984
3063
|
const plan = mapping === void 0 || platform === null || !options.platforms.has(platform) ? null : buildNativeComponent({
|
|
@@ -3202,6 +3281,11 @@ var CAP_COMMAND_ROUTES = {
|
|
|
3202
3281
|
deviceId,
|
|
3203
3282
|
capName: "button"
|
|
3204
3283
|
}) },
|
|
3284
|
+
control: { primary: (deviceId, value) => value.trim().length === 0 ? null : {
|
|
3285
|
+
kind: "cap-control",
|
|
3286
|
+
deviceId,
|
|
3287
|
+
value
|
|
3288
|
+
} },
|
|
3205
3289
|
cover: {
|
|
3206
3290
|
extras: {
|
|
3207
3291
|
position: (deviceId, value) => {
|
|
@@ -3890,6 +3974,28 @@ async function applyCapCommand(device, command) {
|
|
|
3890
3974
|
};
|
|
3891
3975
|
await device.button.press({});
|
|
3892
3976
|
return { ok: true };
|
|
3977
|
+
case "cap-control": return call(device.control, "control", async (control) => {
|
|
3978
|
+
const status = await control.getStatus({});
|
|
3979
|
+
if (status === null || typeof status !== "object") throw new Error("the device reports no control status, so setValue has no kind");
|
|
3980
|
+
const kind = Reflect.get(status, "kind");
|
|
3981
|
+
if (kind === "numeric") {
|
|
3982
|
+
const numeric = Number(command.value);
|
|
3983
|
+
if (!Number.isFinite(numeric)) throw new Error(`control value is not a number: ${command.value}`);
|
|
3984
|
+
await control.setValue({ control: {
|
|
3985
|
+
kind: "numeric",
|
|
3986
|
+
value: numeric
|
|
3987
|
+
} });
|
|
3988
|
+
return;
|
|
3989
|
+
}
|
|
3990
|
+
if (kind === "select" || kind === "text" || kind === "datetime") {
|
|
3991
|
+
await control.setValue({ control: {
|
|
3992
|
+
kind,
|
|
3993
|
+
value: command.value
|
|
3994
|
+
} });
|
|
3995
|
+
return;
|
|
3996
|
+
}
|
|
3997
|
+
throw new Error(`unsupported control kind: ${String(kind)}`);
|
|
3998
|
+
});
|
|
3893
3999
|
case "cover-position": return call(device.cover, "cover", (cover) => cover.setPosition({ position: command.position }));
|
|
3894
4000
|
case "cover-tilt": return call(device.cover, "cover", (cover) => cover.setTiltPosition({ tiltPosition: command.tiltPosition }));
|
|
3895
4001
|
case "cover-verb": return call(device.cover, "cover", (cover) => {
|