@camstack/addon-provider-homeassistant 1.2.659 → 1.2.660
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 +661 -553
- package/dist/addon.mjs +191 -83
- package/dist/ha-export/ha-export.addon.js +71 -71
- package/dist/ha-export/ha-export.addon.mjs +1 -1
- package/dist/{ha-instance-settings-qhCNJbbn.mjs → legacy-integration-rows-BIbFoT26.mjs} +27 -5
- package/dist/{ha-instance-settings-CRvQ5rH6.js → legacy-integration-rows-BWVmjfDO.js} +27 -5
- package/package.json +2 -2
|
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
enumerable: true
|
|
25
25
|
}) : target, mod));
|
|
26
26
|
//#endregion
|
|
27
|
-
const
|
|
27
|
+
const require_legacy_integration_rows = require("../legacy-integration-rows-BWVmjfDO.js");
|
|
28
28
|
let node_crypto = require("node:crypto");
|
|
29
29
|
require("node:zlib");
|
|
30
30
|
let node_fs = require("node:fs");
|
|
@@ -91,7 +91,7 @@ async function applyCameraFunctionWrite(api, deviceId, write, sourceNodeId) {
|
|
|
91
91
|
await api.streamBroker.setDeviceAudioMute.mutate({
|
|
92
92
|
deviceId,
|
|
93
93
|
muted: write.muted
|
|
94
|
-
},
|
|
94
|
+
}, require_legacy_integration_rows.nodePin(sourceNodeId));
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
97
|
}
|
|
@@ -725,8 +725,8 @@ function consumableEntity(key, facet) {
|
|
|
725
725
|
* rather than to an icon for nothing.
|
|
726
726
|
*/
|
|
727
727
|
function consumableForm(item) {
|
|
728
|
-
const declared =
|
|
729
|
-
return
|
|
728
|
+
const declared = require_legacy_integration_rows.ConsumableFormSchema.safeParse(item.form);
|
|
729
|
+
return require_legacy_integration_rows.consumableFormOf({
|
|
730
730
|
...item.kind !== void 0 ? { kind: item.kind } : {},
|
|
731
731
|
...declared.success ? { form: declared.data } : {}
|
|
732
732
|
});
|
|
@@ -739,7 +739,7 @@ function partIcon(key, label) {
|
|
|
739
739
|
function formIcon(item, form) {
|
|
740
740
|
switch (form) {
|
|
741
741
|
case "part": return partIcon(item.key, item.label);
|
|
742
|
-
case "tank": return
|
|
742
|
+
case "tank": return require_legacy_integration_rows.consumableKindOf(item) === "waste" ? "mdi:water-off" : "mdi:water";
|
|
743
743
|
case "product": return "mdi:shaker-outline";
|
|
744
744
|
case "bin": return "mdi:delete";
|
|
745
745
|
}
|
|
@@ -750,8 +750,8 @@ function formIcon(item, form) {
|
|
|
750
750
|
* form this export does not know degrades one icon instead of refusing the
|
|
751
751
|
* whole slice.
|
|
752
752
|
*/
|
|
753
|
-
var ExportConsumableItemSchema =
|
|
754
|
-
var ExportConsumablesSchema =
|
|
753
|
+
var ExportConsumableItemSchema = require_legacy_integration_rows.ConsumableItemSchema.extend({ form: require_legacy_integration_rows.unknown().optional() });
|
|
754
|
+
var ExportConsumablesSchema = require_legacy_integration_rows.object({ items: require_legacy_integration_rows.array(ExportConsumableItemSchema) });
|
|
755
755
|
/**
|
|
756
756
|
* A worn part's life is a diagnostic; a tank's fill is what the device page
|
|
757
757
|
* is for (a vacuum's clean water, a dishwasher's salt), so it is not hidden.
|
|
@@ -764,7 +764,7 @@ function consumableEntities(item) {
|
|
|
764
764
|
capName: "consumables",
|
|
765
765
|
itemKey: item.key
|
|
766
766
|
};
|
|
767
|
-
const kind =
|
|
767
|
+
const kind = require_legacy_integration_rows.consumableKindOf(item);
|
|
768
768
|
const form = consumableForm(item);
|
|
769
769
|
const icon = formIcon(item, form);
|
|
770
770
|
/** What the item IS, on the sensors that describe it (not on a counter or a button). */
|
|
@@ -804,7 +804,7 @@ function consumableEntities(item) {
|
|
|
804
804
|
platform: "sensor",
|
|
805
805
|
label: `${item.label} status`,
|
|
806
806
|
deviceClass: "enum",
|
|
807
|
-
options:
|
|
807
|
+
options: require_legacy_integration_rows.ConsumableStatusSchema.options,
|
|
808
808
|
icon,
|
|
809
809
|
attributes,
|
|
810
810
|
entityCategory: "diagnostic"
|
|
@@ -2405,7 +2405,7 @@ var CAP_ENTITY_MAP = {
|
|
|
2405
2405
|
* failure. `fanMode` and `preset` get no such list at all: they are
|
|
2406
2406
|
* free-form strings, so they stay sensors.
|
|
2407
2407
|
*/
|
|
2408
|
-
options:
|
|
2408
|
+
options: require_legacy_integration_rows.HvacModeSchema.options,
|
|
2409
2409
|
extras: {
|
|
2410
2410
|
"current-temp": {
|
|
2411
2411
|
platform: "sensor",
|
|
@@ -2555,7 +2555,7 @@ var CAP_ENTITY_MAP = {
|
|
|
2555
2555
|
field: "direction",
|
|
2556
2556
|
label: "Direction",
|
|
2557
2557
|
writable: true,
|
|
2558
|
-
options:
|
|
2558
|
+
options: require_legacy_integration_rows.FanDirectionSchema.options,
|
|
2559
2559
|
enabledByDefault: false
|
|
2560
2560
|
}
|
|
2561
2561
|
}
|
|
@@ -2985,7 +2985,7 @@ var CAP_ENTITY_MAP = {
|
|
|
2985
2985
|
field: "repeat",
|
|
2986
2986
|
label: "Repeat",
|
|
2987
2987
|
writable: true,
|
|
2988
|
-
options:
|
|
2988
|
+
options: require_legacy_integration_rows.MediaPlayerRepeatSchema.options,
|
|
2989
2989
|
enabledByDefault: false
|
|
2990
2990
|
},
|
|
2991
2991
|
shuffle: {
|
|
@@ -3481,7 +3481,7 @@ function controlEntitySpecs(slice, quantity) {
|
|
|
3481
3481
|
const min = readFiniteNumber(slice, "min") ?? PERCENT_RANGE.min;
|
|
3482
3482
|
const max = readFiniteNumber(slice, "max") ?? PERCENT_RANGE.max;
|
|
3483
3483
|
const step = readFiniteNumber(slice, "step") ?? PERCENT_RANGE.step;
|
|
3484
|
-
const unit = quantity === void 0 ? void 0 :
|
|
3484
|
+
const unit = quantity === void 0 ? void 0 : require_legacy_integration_rows.baseUnitOf(quantity);
|
|
3485
3485
|
if (min < max && step > 0) return [{
|
|
3486
3486
|
entity: primary,
|
|
3487
3487
|
platform: "number",
|
|
@@ -3803,7 +3803,7 @@ function buildDerivedPlan(device, options = UNNEGOTIATED_PLAN_OPTIONS) {
|
|
|
3803
3803
|
continue;
|
|
3804
3804
|
}
|
|
3805
3805
|
if (cap === "numeric-sensor") {
|
|
3806
|
-
const unit = device.readingQuantity === void 0 ? void 0 :
|
|
3806
|
+
const unit = device.readingQuantity === void 0 ? void 0 : require_legacy_integration_rows.baseUnitOf(device.readingQuantity);
|
|
3807
3807
|
specs.push(...capEntitySpecs(cap).map((spec) => degradeUnsupported(unit === void 0 ? spec : {
|
|
3808
3808
|
...spec,
|
|
3809
3809
|
unit
|
|
@@ -3878,7 +3878,7 @@ function buildDevicePlan(device, options = UNNEGOTIATED_PLAN_OPTIONS) {
|
|
|
3878
3878
|
* was.
|
|
3879
3879
|
*/
|
|
3880
3880
|
/** The camera function ids, keyed by the entity slug the catalog emits. */
|
|
3881
|
-
var CAMERA_SWITCH_BY_SLUG = Object.fromEntries(
|
|
3881
|
+
var CAMERA_SWITCH_BY_SLUG = Object.fromEntries(require_legacy_integration_rows.CAMERA_SWITCH_ORDER.map((id) => [toSlug(id), id]));
|
|
3882
3882
|
var PTZ_DIRECTION_BY_ENTITY = Object.fromEntries(PTZ_BUTTONS.map((entity) => [entity, entity.slice(4)]));
|
|
3883
3883
|
function parseBool(value) {
|
|
3884
3884
|
const lower = value.trim().toLowerCase();
|
|
@@ -3941,7 +3941,7 @@ function parseAlarmAction(value) {
|
|
|
3941
3941
|
if (lower === "disarm" || lower === "disarmed") return { kind: "disarm" };
|
|
3942
3942
|
if (lower === "trigger" || lower === "triggered") return { kind: "trigger" };
|
|
3943
3943
|
const withoutPrefix = lower.startsWith("armed_") ? lower.slice(6) : lower.startsWith("arm_") ? lower.slice(4) : lower;
|
|
3944
|
-
const mode =
|
|
3944
|
+
const mode = require_legacy_integration_rows.AlarmArmModeSchema.safeParse(withoutPrefix);
|
|
3945
3945
|
return mode.success ? {
|
|
3946
3946
|
kind: "arm",
|
|
3947
3947
|
mode: mode.data
|
|
@@ -4090,7 +4090,7 @@ var CAP_COMMAND_ROUTES = {
|
|
|
4090
4090
|
},
|
|
4091
4091
|
"climate-control": {
|
|
4092
4092
|
primary: (deviceId, value) => {
|
|
4093
|
-
const mode = parseEnum(
|
|
4093
|
+
const mode = parseEnum(require_legacy_integration_rows.HvacModeSchema, value);
|
|
4094
4094
|
return mode === null ? null : {
|
|
4095
4095
|
kind: "climate-mode",
|
|
4096
4096
|
deviceId,
|
|
@@ -4205,7 +4205,7 @@ var CAP_COMMAND_ROUTES = {
|
|
|
4205
4205
|
};
|
|
4206
4206
|
},
|
|
4207
4207
|
direction: (deviceId, value) => {
|
|
4208
|
-
const direction = parseEnum(
|
|
4208
|
+
const direction = parseEnum(require_legacy_integration_rows.FanDirectionSchema, value);
|
|
4209
4209
|
return direction === null ? null : {
|
|
4210
4210
|
kind: "fan-direction",
|
|
4211
4211
|
deviceId,
|
|
@@ -4409,7 +4409,7 @@ var CAP_COMMAND_ROUTES = {
|
|
|
4409
4409
|
};
|
|
4410
4410
|
},
|
|
4411
4411
|
repeat: (deviceId, value) => {
|
|
4412
|
-
const repeat = parseEnum(
|
|
4412
|
+
const repeat = parseEnum(require_legacy_integration_rows.MediaPlayerRepeatSchema, value);
|
|
4413
4413
|
return repeat === null ? null : {
|
|
4414
4414
|
kind: "media-repeat",
|
|
4415
4415
|
deviceId,
|
|
@@ -5001,7 +5001,7 @@ async function planDropPublicBaseUrl(ports) {
|
|
|
5001
5001
|
op: "deleteKeys",
|
|
5002
5002
|
scope: ADDON_SETTINGS_TABLE,
|
|
5003
5003
|
keys: present.map(rowId),
|
|
5004
|
-
precondition:
|
|
5004
|
+
precondition: require_legacy_integration_rows.preconditionOf(Object.fromEntries(present.map((key) => [rowId(key), {
|
|
5005
5005
|
addonId: HA_EXPORT_ADDON_ID,
|
|
5006
5006
|
key,
|
|
5007
5007
|
value: stored[key]
|
|
@@ -5231,7 +5231,7 @@ async function planDropPerBrokerFlags(ports) {
|
|
|
5231
5231
|
op: "deleteKeys",
|
|
5232
5232
|
scope: ADDON_SETTINGS_TABLE,
|
|
5233
5233
|
keys: drop.map((entry) => rowId(entry.storeKey)),
|
|
5234
|
-
precondition:
|
|
5234
|
+
precondition: require_legacy_integration_rows.preconditionOf(Object.fromEntries(drop.map((entry) => [rowId(entry.storeKey), {
|
|
5235
5235
|
addonId: HA_EXPORT_ADDON_ID,
|
|
5236
5236
|
key: entry.storeKey,
|
|
5237
5237
|
value: entry.value
|
|
@@ -5257,15 +5257,15 @@ var HA_EXPORT_TARGETS_KIND_NAME = "ha-export-targets";
|
|
|
5257
5257
|
var HA_TARGET_KIND = "ha-target";
|
|
5258
5258
|
var TARGET_ID_PREFIX = "hae_";
|
|
5259
5259
|
/** The schema is checked against the interface by its annotation: a drifted field fails the typecheck. */
|
|
5260
|
-
var HaExportTargetBodySchema =
|
|
5261
|
-
name:
|
|
5262
|
-
connectionId:
|
|
5263
|
-
mediaRole:
|
|
5264
|
-
reconcileIntervalSec:
|
|
5265
|
-
devices:
|
|
5266
|
-
enabled:
|
|
5260
|
+
var HaExportTargetBodySchema = require_legacy_integration_rows.object({
|
|
5261
|
+
name: require_legacy_integration_rows.string().min(1),
|
|
5262
|
+
connectionId: require_legacy_integration_rows.string(),
|
|
5263
|
+
mediaRole: require_legacy_integration_rows._enum(HA_MEDIA_ROLES),
|
|
5264
|
+
reconcileIntervalSec: require_legacy_integration_rows.number(),
|
|
5265
|
+
devices: require_legacy_integration_rows.array(require_legacy_integration_rows.string()),
|
|
5266
|
+
enabled: require_legacy_integration_rows.boolean().optional()
|
|
5267
5267
|
});
|
|
5268
|
-
var haExportTargetsKind =
|
|
5268
|
+
var haExportTargetsKind = require_legacy_integration_rows.defineEntryKind(HA_EXPORT_TARGETS_KIND_NAME, {
|
|
5269
5269
|
title: "Home Assistant export targets",
|
|
5270
5270
|
nameField: "name",
|
|
5271
5271
|
schema: HaExportTargetBodySchema,
|
|
@@ -5604,7 +5604,7 @@ async function planDropMovedLinks(ports) {
|
|
|
5604
5604
|
op: "deleteKeys",
|
|
5605
5605
|
scope: ADDON_SETTINGS_TABLE,
|
|
5606
5606
|
keys: present.map(rowId),
|
|
5607
|
-
precondition:
|
|
5607
|
+
precondition: require_legacy_integration_rows.preconditionOf(Object.fromEntries(present.map((key) => [rowId(key), {
|
|
5608
5608
|
addonId: HA_EXPORT_ADDON_ID,
|
|
5609
5609
|
key,
|
|
5610
5610
|
value: stored[key]
|
|
@@ -5740,13 +5740,13 @@ var ADDON_MIGRATIONS = [
|
|
|
5740
5740
|
* outside `migrations/` names it (`no-legacy-links-reader.spec.ts`).
|
|
5741
5741
|
*/
|
|
5742
5742
|
var HA_EXPORT_LINKS_KIND_NAME = "ha-export-links";
|
|
5743
|
-
var HaExportLinksBodySchema =
|
|
5744
|
-
name:
|
|
5745
|
-
exportTo:
|
|
5746
|
-
mediaRole:
|
|
5747
|
-
devices:
|
|
5743
|
+
var HaExportLinksBodySchema = require_legacy_integration_rows.object({
|
|
5744
|
+
name: require_legacy_integration_rows.string().min(1),
|
|
5745
|
+
exportTo: require_legacy_integration_rows.boolean(),
|
|
5746
|
+
mediaRole: require_legacy_integration_rows._enum(HA_MEDIA_ROLES),
|
|
5747
|
+
devices: require_legacy_integration_rows.array(require_legacy_integration_rows.string())
|
|
5748
5748
|
});
|
|
5749
|
-
var haExportLinksKind =
|
|
5749
|
+
var haExportLinksKind = require_legacy_integration_rows.defineEntryKind(HA_EXPORT_LINKS_KIND_NAME, {
|
|
5750
5750
|
title: "Home Assistant export links (retired)",
|
|
5751
5751
|
nameField: "name",
|
|
5752
5752
|
schema: HaExportLinksBodySchema,
|
|
@@ -5781,7 +5781,7 @@ async function readAllLinks(handle) {
|
|
|
5781
5781
|
function haExportMigrationPorts(deps) {
|
|
5782
5782
|
return {
|
|
5783
5783
|
readStored: deps.readStored,
|
|
5784
|
-
...
|
|
5784
|
+
...require_legacy_integration_rows.haInstanceSettingsPortsOver(deps.api.integrations),
|
|
5785
5785
|
warn: deps.warn,
|
|
5786
5786
|
putLinks: async (brokerId, body) => {
|
|
5787
5787
|
if (await deps.links.get(brokerId) !== null) return "exists";
|
|
@@ -5791,7 +5791,7 @@ function haExportMigrationPorts(deps) {
|
|
|
5791
5791
|
data: body
|
|
5792
5792
|
}, { ifRev: 0 });
|
|
5793
5793
|
} catch (err) {
|
|
5794
|
-
if (err instanceof
|
|
5794
|
+
if (err instanceof require_legacy_integration_rows.RevConflictError) return "exists";
|
|
5795
5795
|
throw err;
|
|
5796
5796
|
}
|
|
5797
5797
|
return "created";
|
|
@@ -5805,7 +5805,7 @@ function haExportMigrationPorts(deps) {
|
|
|
5805
5805
|
data: body
|
|
5806
5806
|
}, { ifRev: 0 });
|
|
5807
5807
|
} catch (err) {
|
|
5808
|
-
if (err instanceof
|
|
5808
|
+
if (err instanceof require_legacy_integration_rows.RevConflictError) return "exists";
|
|
5809
5809
|
throw err;
|
|
5810
5810
|
}
|
|
5811
5811
|
return "created";
|
|
@@ -5887,7 +5887,7 @@ function buildTargetForm() {
|
|
|
5887
5887
|
* may push to one Home Assistant.
|
|
5888
5888
|
*/
|
|
5889
5889
|
function openTargetInstances(records, deps) {
|
|
5890
|
-
return new
|
|
5890
|
+
return new require_legacy_integration_rows.RecordIntegrationInstances(records, haExportTargetsKind, {
|
|
5891
5891
|
description: {
|
|
5892
5892
|
role: "services",
|
|
5893
5893
|
instanceMode: "multiple",
|
|
@@ -6646,7 +6646,7 @@ function reduceLastTriggers(rows) {
|
|
|
6646
6646
|
function macroOf(className) {
|
|
6647
6647
|
const lower = className.toLowerCase();
|
|
6648
6648
|
if (EXPORTED_MACROS.includes(lower)) return lower;
|
|
6649
|
-
const mapped =
|
|
6649
|
+
const mapped = require_legacy_integration_rows.COCO_TO_MACRO.mapping[lower];
|
|
6650
6650
|
return typeof mapped === "string" ? mapped : null;
|
|
6651
6651
|
}
|
|
6652
6652
|
function iso(timestamp) {
|
|
@@ -7795,7 +7795,7 @@ var ExportedEntities = class {
|
|
|
7795
7795
|
this.ports.logger.warn("homeassistant-export: exported entities not reconciled — a list was unanswered", { meta: { error: errMsg$1(err) } });
|
|
7796
7796
|
return;
|
|
7797
7797
|
}
|
|
7798
|
-
const { dropped } =
|
|
7798
|
+
const { dropped } = require_legacy_integration_rows.pruneDeletedEntities([...this.state.actions.map((e) => ({
|
|
7799
7799
|
kind: "action",
|
|
7800
7800
|
actionId: e.actionId
|
|
7801
7801
|
})), ...this.state.targets.map((e) => ({
|
|
@@ -7867,7 +7867,7 @@ var ExportedEntities = class {
|
|
|
7867
7867
|
const action = this.state.actions.find((e) => actionEntity(e.actionId) === entity);
|
|
7868
7868
|
if (action !== void 0) return {
|
|
7869
7869
|
handled: true,
|
|
7870
|
-
applied: (await
|
|
7870
|
+
applied: (await require_legacy_integration_rows.runExportedAction(this.ports.api, this.ports.logger, {
|
|
7871
7871
|
exporter: EXPORTER,
|
|
7872
7872
|
actionId: action.actionId
|
|
7873
7873
|
})).status === "started"
|
|
@@ -7875,7 +7875,7 @@ var ExportedEntities = class {
|
|
|
7875
7875
|
const target = this.state.targets.find((e) => targetEntity(e.targetId) === entity);
|
|
7876
7876
|
if (target !== void 0) return {
|
|
7877
7877
|
handled: true,
|
|
7878
|
-
applied: (await
|
|
7878
|
+
applied: (await require_legacy_integration_rows.sendToExportedTarget(this.ports.api, this.ports.logger, {
|
|
7879
7879
|
exporter: EXPORTER,
|
|
7880
7880
|
targetId: target.targetId,
|
|
7881
7881
|
notification: { body: value }
|
|
@@ -7926,7 +7926,7 @@ var SUPPORTED_DEVICE_KINDS = [
|
|
|
7926
7926
|
"image",
|
|
7927
7927
|
"pet-feeder",
|
|
7928
7928
|
"hub",
|
|
7929
|
-
...
|
|
7929
|
+
...require_legacy_integration_rows.PLUG_APPLIANCE_TYPES
|
|
7930
7930
|
];
|
|
7931
7931
|
//#endregion
|
|
7932
7932
|
//#region src/ha-export/ha-export.addon.ts
|
|
@@ -7991,7 +7991,7 @@ var DEFAULT_CONFIG = { exportedEntities: {
|
|
|
7991
7991
|
actions: [],
|
|
7992
7992
|
targets: []
|
|
7993
7993
|
} };
|
|
7994
|
-
var HaExportAddon = class extends
|
|
7994
|
+
var HaExportAddon = class extends require_legacy_integration_rows.BaseAddon {
|
|
7995
7995
|
links = /* @__PURE__ */ new Map();
|
|
7996
7996
|
instances = null;
|
|
7997
7997
|
/** The Home Assistant connections (broker ids) the last `broker.list` answered. */
|
|
@@ -8105,7 +8105,7 @@ var HaExportAddon = class extends require_ha_instance_settings.BaseAddon {
|
|
|
8105
8105
|
await records.declare({ "ha-export-targets": haExportTargetsKind });
|
|
8106
8106
|
const targetsHandle = records.kind(haExportTargetsKind);
|
|
8107
8107
|
const legacyLinks = await declareLegacyLinks(records);
|
|
8108
|
-
await this.runMigrations(
|
|
8108
|
+
await this.runMigrations(require_legacy_integration_rows.defineAddonMigrations(ADDON_MIGRATIONS, haExportMigrationPorts({
|
|
8109
8109
|
readStored: async () => this.resolveGlobalStore(),
|
|
8110
8110
|
api: this.ctx.api,
|
|
8111
8111
|
links: legacyLinks,
|
|
@@ -8122,7 +8122,7 @@ var HaExportAddon = class extends require_ha_instance_settings.BaseAddon {
|
|
|
8122
8122
|
health: (id, body) => this.targetHealth(id, body),
|
|
8123
8123
|
onChanged: (id, change) => this.onTargetChanged(id, change)
|
|
8124
8124
|
});
|
|
8125
|
-
const secret = this.state("haExportMediaSecret",
|
|
8125
|
+
const secret = this.state("haExportMediaSecret", require_legacy_integration_rows.string(), "");
|
|
8126
8126
|
const existing = await secret.get();
|
|
8127
8127
|
if (existing.length === 0) {
|
|
8128
8128
|
const minted = randomSecret();
|
|
@@ -8155,9 +8155,9 @@ var HaExportAddon = class extends require_ha_instance_settings.BaseAddon {
|
|
|
8155
8155
|
this.exportedEntities = exportedEntities;
|
|
8156
8156
|
return [
|
|
8157
8157
|
{
|
|
8158
|
-
capability:
|
|
8158
|
+
capability: require_legacy_integration_rows.deviceExportCapability,
|
|
8159
8159
|
provider: {
|
|
8160
|
-
getStatus: async (input) => this.buildStatus(this.targetScope(
|
|
8160
|
+
getStatus: async (input) => this.buildStatus(this.targetScope(require_legacy_integration_rows.statusInstanceOf(input))),
|
|
8161
8161
|
listInstances: async () => this.book().ids().map((id) => ({
|
|
8162
8162
|
instanceId: id,
|
|
8163
8163
|
name: this.book().name(id),
|
|
@@ -8203,12 +8203,12 @@ var HaExportAddon = class extends require_ha_instance_settings.BaseAddon {
|
|
|
8203
8203
|
}
|
|
8204
8204
|
},
|
|
8205
8205
|
{
|
|
8206
|
-
capability:
|
|
8206
|
+
capability: require_legacy_integration_rows.integrationInstancesCapability,
|
|
8207
8207
|
provider: this.requireInstances().toProvider()
|
|
8208
8208
|
},
|
|
8209
8209
|
{
|
|
8210
|
-
capability:
|
|
8211
|
-
provider:
|
|
8210
|
+
capability: require_legacy_integration_rows.addonRoutesCapability,
|
|
8211
|
+
provider: require_legacy_integration_rows.buildAddonRouteProvider(ADDON_ID, [{
|
|
8212
8212
|
method: "POST",
|
|
8213
8213
|
path: "/command",
|
|
8214
8214
|
access: "authenticated",
|
|
@@ -8219,7 +8219,7 @@ var HaExportAddon = class extends require_ha_instance_settings.BaseAddon {
|
|
|
8219
8219
|
}])
|
|
8220
8220
|
},
|
|
8221
8221
|
{
|
|
8222
|
-
capability:
|
|
8222
|
+
capability: require_legacy_integration_rows.oauthIntegrationCapability,
|
|
8223
8223
|
provider: { getDescriptor: async () => HOME_ASSISTANT_OAUTH_INTEGRATION }
|
|
8224
8224
|
}
|
|
8225
8225
|
];
|
|
@@ -8248,16 +8248,16 @@ var HaExportAddon = class extends require_ha_instance_settings.BaseAddon {
|
|
|
8248
8248
|
return this.instances;
|
|
8249
8249
|
}
|
|
8250
8250
|
wireListeners() {
|
|
8251
|
-
this.subscribe({ category:
|
|
8251
|
+
this.subscribe({ category: require_legacy_integration_rows.EventCategory.DeviceStateChanged }, (event) => {
|
|
8252
8252
|
this.onSliceChanged(event.data);
|
|
8253
8253
|
});
|
|
8254
|
-
this.subscribe({ category:
|
|
8254
|
+
this.subscribe({ category: require_legacy_integration_rows.EventCategory.DeviceOnline }, (event) => {
|
|
8255
8255
|
this.onOnlineChanged(event.data, true);
|
|
8256
8256
|
});
|
|
8257
|
-
this.subscribe({ category:
|
|
8257
|
+
this.subscribe({ category: require_legacy_integration_rows.EventCategory.DeviceOffline }, (event) => {
|
|
8258
8258
|
this.onOnlineChanged(event.data, false);
|
|
8259
8259
|
});
|
|
8260
|
-
this.subscribe({ category:
|
|
8260
|
+
this.subscribe({ category: require_legacy_integration_rows.EventCategory.MotionOnMotionChanged }, (event) => {
|
|
8261
8261
|
this.onMotion(event.data);
|
|
8262
8262
|
});
|
|
8263
8263
|
/**
|
|
@@ -8266,13 +8266,13 @@ var HaExportAddon = class extends require_ha_instance_settings.BaseAddon {
|
|
|
8266
8266
|
* the entity existed and effectively never moved. It also carries the
|
|
8267
8267
|
* window LEVEL, which nothing else on the export path does.
|
|
8268
8268
|
*/
|
|
8269
|
-
this.subscribe({ category:
|
|
8269
|
+
this.subscribe({ category: require_legacy_integration_rows.EventCategory.PipelineAudioInferenceResult }, (event) => {
|
|
8270
8270
|
this.onAudioWindow(event.data);
|
|
8271
8271
|
});
|
|
8272
|
-
this.subscribe({ category:
|
|
8272
|
+
this.subscribe({ category: require_legacy_integration_rows.EventCategory.PipelineAnalyticsTrackLifecycle }, (event) => {
|
|
8273
8273
|
this.onTrackLifecycle(event.data);
|
|
8274
8274
|
});
|
|
8275
|
-
this.subscribe({ category:
|
|
8275
|
+
this.subscribe({ category: require_legacy_integration_rows.EventCategory.ZoneAnalyticsOccupancyChanged }, (event) => {
|
|
8276
8276
|
this.onZoneOccupancy(event.data);
|
|
8277
8277
|
});
|
|
8278
8278
|
/**
|
|
@@ -8281,11 +8281,11 @@ var HaExportAddon = class extends require_ha_instance_settings.BaseAddon {
|
|
|
8281
8281
|
* rather than a state push.
|
|
8282
8282
|
*/
|
|
8283
8283
|
for (const category of [
|
|
8284
|
-
|
|
8285
|
-
|
|
8286
|
-
|
|
8287
|
-
|
|
8288
|
-
|
|
8284
|
+
require_legacy_integration_rows.EventCategory.DeviceRegistered,
|
|
8285
|
+
require_legacy_integration_rows.EventCategory.DeviceUnregistered,
|
|
8286
|
+
require_legacy_integration_rows.EventCategory.DeviceBindingsChanged,
|
|
8287
|
+
require_legacy_integration_rows.EventCategory.DeviceMetaChanged,
|
|
8288
|
+
require_legacy_integration_rows.EventCategory.BrokerStatusChanged
|
|
8289
8289
|
]) this.subscribe({ category }, () => {
|
|
8290
8290
|
this.reconcileSoon();
|
|
8291
8291
|
});
|
|
@@ -9398,7 +9398,7 @@ var HaExportAddon = class extends require_ha_instance_settings.BaseAddon {
|
|
|
9398
9398
|
*/
|
|
9399
9399
|
capSlices: snapshot,
|
|
9400
9400
|
itemEntities: items.entities,
|
|
9401
|
-
...
|
|
9401
|
+
...require_legacy_integration_rows.isReadingQuantity(readingQuantity) ? { readingQuantity } : {}
|
|
9402
9402
|
},
|
|
9403
9403
|
heldBack
|
|
9404
9404
|
};
|
|
@@ -9632,7 +9632,7 @@ var HaExportAddon = class extends require_ha_instance_settings.BaseAddon {
|
|
|
9632
9632
|
maskEnabled: privacySlice["enabled"] === true,
|
|
9633
9633
|
audioEnabled: typeof privacySlice["audioEnabled"] === "boolean" ? privacySlice["audioEnabled"] : null
|
|
9634
9634
|
};
|
|
9635
|
-
const brokerAudioMuted = sourceNodeId === null ? null : await this.ctx.api.streamBroker.getDeviceAudioMute.query({ deviceId },
|
|
9635
|
+
const brokerAudioMuted = sourceNodeId === null ? null : await this.ctx.api.streamBroker.getDeviceAudioMute.query({ deviceId }, require_legacy_integration_rows.nodePin(sourceNodeId)).then((r) => r.muted).catch((err) => {
|
|
9636
9636
|
this.ctx.logger.warn("ha-export: could not read broker audio mute, the broker-audio function degrades", {
|
|
9637
9637
|
tags: { deviceId },
|
|
9638
9638
|
meta: {
|
|
@@ -9683,7 +9683,7 @@ var HaExportAddon = class extends require_ha_instance_settings.BaseAddon {
|
|
|
9683
9683
|
* reasoning.
|
|
9684
9684
|
*/
|
|
9685
9685
|
async refreshBrokers() {
|
|
9686
|
-
const haBrokers = await
|
|
9686
|
+
const haBrokers = await require_legacy_integration_rows.listHomeAssistantBrokers((input) => this.ctx.api.broker.list.query(input));
|
|
9687
9687
|
/**
|
|
9688
9688
|
* NEVER treat an empty enumeration as "the connections are gone".
|
|
9689
9689
|
*
|
|
@@ -10064,7 +10064,7 @@ var HaExportAddon = class extends require_ha_instance_settings.BaseAddon {
|
|
|
10064
10064
|
}
|
|
10065
10065
|
switch (command.kind) {
|
|
10066
10066
|
case "camera-function": {
|
|
10067
|
-
const parsed =
|
|
10067
|
+
const parsed = require_legacy_integration_rows.CameraSwitchIdSchema.safeParse(command.switchId);
|
|
10068
10068
|
if (!parsed.success) {
|
|
10069
10069
|
this.ctx.logger.warn("ha-export: dropping a command for an unknown camera function", {
|
|
10070
10070
|
tags: { deviceId: command.deviceId },
|
|
@@ -10345,7 +10345,7 @@ var HaExportAddon = class extends require_ha_instance_settings.BaseAddon {
|
|
|
10345
10345
|
*/
|
|
10346
10346
|
targetScope(instanceId) {
|
|
10347
10347
|
if (instanceId === void 0) return this.enabledTargetIds();
|
|
10348
|
-
if (!this.knownTargetIds().has(instanceId)) throw new
|
|
10348
|
+
if (!this.knownTargetIds().has(instanceId)) throw new require_legacy_integration_rows.ExportInstanceUnknownError("provider-homeassistant", instanceId);
|
|
10349
10349
|
return [instanceId];
|
|
10350
10350
|
}
|
|
10351
10351
|
exposedDeviceRows(scope) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { F as buildAddonRouteProvider, It as statusInstanceOf, Jt as BaseAddon, Ot as runExportedAction, Pt as sendToExportedTarget, Qt as baseUnitOf, Sn as EventCategory, U as consumableFormOf, W as consumableKindOf, X as deviceExportCapability, Zt as RevConflictError, _ as HvacModeSchema, _t as oauthIntegrationCapability, a as AlarmArmModeSchema, an as nodePin, bt as preconditionOf, c as CAMERA_SWITCH_ORDER, cn as boolean, ct as integrationInstancesCapability, d as ConsumableFormSchema, dn as number, en as defineAddonMigrations, f as ConsumableItemSchema, fn as object, g as FanDirectionSchema, gn as unknown, h as ExportInstanceUnknownError, i as listHomeAssistantBrokers, in as isReadingQuantity, l as COCO_TO_MACRO, mn as string, on as _enum, p as ConsumableStatusSchema, sn as array, t as haInstanceSettingsPortsOver, tn as defineEntryKind, u as CameraSwitchIdSchema, v as MediaPlayerRepeatSchema, w as addonRoutesCapability, wt as pruneDeletedEntities, x as RecordIntegrationInstances, y as PLUG_APPLIANCE_TYPES } from "../
|
|
1
|
+
import { F as buildAddonRouteProvider, It as statusInstanceOf, Jt as BaseAddon, Ot as runExportedAction, Pt as sendToExportedTarget, Qt as baseUnitOf, Sn as EventCategory, U as consumableFormOf, W as consumableKindOf, X as deviceExportCapability, Zt as RevConflictError, _ as HvacModeSchema, _t as oauthIntegrationCapability, a as AlarmArmModeSchema, an as nodePin, bt as preconditionOf, c as CAMERA_SWITCH_ORDER, cn as boolean, ct as integrationInstancesCapability, d as ConsumableFormSchema, dn as number, en as defineAddonMigrations, f as ConsumableItemSchema, fn as object, g as FanDirectionSchema, gn as unknown, h as ExportInstanceUnknownError, i as listHomeAssistantBrokers, in as isReadingQuantity, l as COCO_TO_MACRO, mn as string, on as _enum, p as ConsumableStatusSchema, sn as array, t as haInstanceSettingsPortsOver, tn as defineEntryKind, u as CameraSwitchIdSchema, v as MediaPlayerRepeatSchema, w as addonRoutesCapability, wt as pruneDeletedEntities, x as RecordIntegrationInstances, y as PLUG_APPLIANCE_TYPES } from "../legacy-integration-rows-BIbFoT26.mjs";
|
|
2
2
|
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
3
3
|
import "node:zlib";
|
|
4
4
|
import "node:fs";
|
|
@@ -11996,7 +11996,7 @@ object({
|
|
|
11996
11996
|
params: record(string(), union([string(), number()])).optional()
|
|
11997
11997
|
});
|
|
11998
11998
|
//#endregion
|
|
11999
|
-
//#region ../types/dist/composition-
|
|
11999
|
+
//#region ../types/dist/composition-pOHbTzRB.mjs
|
|
12000
12000
|
/**
|
|
12001
12001
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
12002
12002
|
*
|
|
@@ -50855,6 +50855,9 @@ var RunningProposalEvidenceSchema = object({
|
|
|
50855
50855
|
runsFound: number().int().nonnegative(),
|
|
50856
50856
|
pausesFound: number().int().nonnegative(),
|
|
50857
50857
|
longestPauseMs: number().nonnegative(),
|
|
50858
|
+
/** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
|
|
50859
|
+
pulsesFound: number().int().nonnegative(),
|
|
50860
|
+
longestPulseMs: number().nonnegative(),
|
|
50858
50861
|
idleFloorW: number(),
|
|
50859
50862
|
noiseCeilingW: number(),
|
|
50860
50863
|
plateauW: number(),
|
|
@@ -81310,11 +81313,15 @@ function runningFromMediaPlayer(state, previous, fetchedAt, transitionAt) {
|
|
|
81310
81313
|
* 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
|
|
81311
81314
|
* near F. A device that is not near one level most of the time has no floor.
|
|
81312
81315
|
* 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
|
|
81313
|
-
* 3.
|
|
81314
|
-
*
|
|
81316
|
+
* 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
|
|
81317
|
+
* display waking): it is neither a run nor a pause. Among the remaining
|
|
81318
|
+
* episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
|
|
81319
|
+
* two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
|
|
81320
|
+
* a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
|
|
81321
|
+
* is no run.
|
|
81315
81322
|
* 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
|
|
81316
|
-
* grid a person would type; stop dwell covers the longest pause
|
|
81317
|
-
* covers the longest standby blip above T.
|
|
81323
|
+
* grid a person would type; stop dwell covers the longest pause and the
|
|
81324
|
+
* kind's floor; start dwell covers the longest pulse and standby blip above T.
|
|
81318
81325
|
* 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
|
|
81319
81326
|
* run must hold exactly one true interval and nothing may flap outside.
|
|
81320
81327
|
*/
|
|
@@ -81325,6 +81332,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
|
|
|
81325
81332
|
30 * SECOND_MS;
|
|
81326
81333
|
60 * SECOND_MS;
|
|
81327
81334
|
20 * MINUTE_MS$1;
|
|
81335
|
+
90 * SECOND_MS;
|
|
81336
|
+
30 * MINUTE_MS$1;
|
|
81337
|
+
10 * MINUTE_MS$1;
|
|
81338
|
+
DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
|
|
81328
81339
|
10 * SECOND_MS;
|
|
81329
81340
|
10 * SECOND_MS;
|
|
81330
81341
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
@@ -98417,6 +98428,17 @@ function haInstanceSettingsPortsOver(api) {
|
|
|
98417
98428
|
skipRestart: true
|
|
98418
98429
|
});
|
|
98419
98430
|
return true;
|
|
98431
|
+
},
|
|
98432
|
+
clearInstanceSettingsKeys: async (integrationId, keys) => {
|
|
98433
|
+
if (!(await api.list.query()).some((i) => i.id === integrationId && i.addonId === "provider-homeassistant")) return false;
|
|
98434
|
+
const stored = await api.getSettings.query({ id: integrationId });
|
|
98435
|
+
const drop = new Set(keys);
|
|
98436
|
+
await api.setSettings.mutate({
|
|
98437
|
+
id: integrationId,
|
|
98438
|
+
settings: Object.fromEntries(Object.entries(stored).filter(([key]) => !drop.has(key))),
|
|
98439
|
+
skipRestart: true
|
|
98440
|
+
});
|
|
98441
|
+
return true;
|
|
98420
98442
|
}
|
|
98421
98443
|
};
|
|
98422
98444
|
}
|
|
@@ -11997,7 +11997,7 @@ object({
|
|
|
11997
11997
|
params: record(string(), union([string(), number()])).optional()
|
|
11998
11998
|
});
|
|
11999
11999
|
//#endregion
|
|
12000
|
-
//#region ../types/dist/composition-
|
|
12000
|
+
//#region ../types/dist/composition-pOHbTzRB.mjs
|
|
12001
12001
|
/**
|
|
12002
12002
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
12003
12003
|
*
|
|
@@ -50856,6 +50856,9 @@ var RunningProposalEvidenceSchema = object({
|
|
|
50856
50856
|
runsFound: number().int().nonnegative(),
|
|
50857
50857
|
pausesFound: number().int().nonnegative(),
|
|
50858
50858
|
longestPauseMs: number().nonnegative(),
|
|
50859
|
+
/** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
|
|
50860
|
+
pulsesFound: number().int().nonnegative(),
|
|
50861
|
+
longestPulseMs: number().nonnegative(),
|
|
50859
50862
|
idleFloorW: number(),
|
|
50860
50863
|
noiseCeilingW: number(),
|
|
50861
50864
|
plateauW: number(),
|
|
@@ -81311,11 +81314,15 @@ function runningFromMediaPlayer(state, previous, fetchedAt, transitionAt) {
|
|
|
81311
81314
|
* 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
|
|
81312
81315
|
* near F. A device that is not near one level most of the time has no floor.
|
|
81313
81316
|
* 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
|
|
81314
|
-
* 3.
|
|
81315
|
-
*
|
|
81317
|
+
* 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
|
|
81318
|
+
* display waking): it is neither a run nor a pause. Among the remaining
|
|
81319
|
+
* episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
|
|
81320
|
+
* two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
|
|
81321
|
+
* a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
|
|
81322
|
+
* is no run.
|
|
81316
81323
|
* 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
|
|
81317
|
-
* grid a person would type; stop dwell covers the longest pause
|
|
81318
|
-
* covers the longest standby blip above T.
|
|
81324
|
+
* grid a person would type; stop dwell covers the longest pause and the
|
|
81325
|
+
* kind's floor; start dwell covers the longest pulse and standby blip above T.
|
|
81319
81326
|
* 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
|
|
81320
81327
|
* run must hold exactly one true interval and nothing may flap outside.
|
|
81321
81328
|
*/
|
|
@@ -81326,6 +81333,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
|
|
|
81326
81333
|
30 * SECOND_MS;
|
|
81327
81334
|
60 * SECOND_MS;
|
|
81328
81335
|
20 * MINUTE_MS$1;
|
|
81336
|
+
90 * SECOND_MS;
|
|
81337
|
+
30 * MINUTE_MS$1;
|
|
81338
|
+
10 * MINUTE_MS$1;
|
|
81339
|
+
DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
|
|
81329
81340
|
10 * SECOND_MS;
|
|
81330
81341
|
10 * SECOND_MS;
|
|
81331
81342
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
@@ -98418,6 +98429,17 @@ function haInstanceSettingsPortsOver(api) {
|
|
|
98418
98429
|
skipRestart: true
|
|
98419
98430
|
});
|
|
98420
98431
|
return true;
|
|
98432
|
+
},
|
|
98433
|
+
clearInstanceSettingsKeys: async (integrationId, keys) => {
|
|
98434
|
+
if (!(await api.list.query()).some((i) => i.id === integrationId && i.addonId === "provider-homeassistant")) return false;
|
|
98435
|
+
const stored = await api.getSettings.query({ id: integrationId });
|
|
98436
|
+
const drop = new Set(keys);
|
|
98437
|
+
await api.setSettings.mutate({
|
|
98438
|
+
id: integrationId,
|
|
98439
|
+
settings: Object.fromEntries(Object.entries(stored).filter(([key]) => !drop.has(key))),
|
|
98440
|
+
skipRestart: true
|
|
98441
|
+
});
|
|
98442
|
+
return true;
|
|
98421
98443
|
}
|
|
98422
98444
|
};
|
|
98423
98445
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-homeassistant",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.660",
|
|
4
4
|
"description": "Home Assistant device provider addon for CamStack",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"description": "Device provider (import) + native entity export (push). Two addons, one bundle, separate processes."
|
|
138
138
|
},
|
|
139
139
|
"requires": {
|
|
140
|
-
"server": ">=1.2.
|
|
140
|
+
"server": ">=1.2.769"
|
|
141
141
|
}
|
|
142
142
|
},
|
|
143
143
|
"files": [
|