@camstack/addon-provider-homeassistant 1.2.155 → 1.2.157
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 +277 -76
- package/dist/addon.mjs +277 -76
- package/dist/{dist-DqKiElqb.mjs → dist-BgTykMb6.mjs} +144 -13
- package/dist/{dist-CERTsNmo.js → dist-M6hP_tw3.js} +149 -12
- 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
|
@@ -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-M6hP_tw3.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,
|
|
1
|
+
import { $ as oauthIntegrationCapability, C as buildAddonRouteProvider, Ft as EventCategory, I as deviceExportCapability, St as nodePin, a as COCO_TO_MACRO, bt as BaseAddon, c as FanDirectionSchema, i as CAMERA_SWITCH_ORDER, jt as string, l as HvacModeSchema, o as CameraSwitchIdSchema, p as addonRoutesCapability, t as AlarmArmModeSchema, u as MediaPlayerRepeatSchema } from "../dist-BgTykMb6.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) => {
|