@camstack/addon-provider-homeassistant 1.2.639 → 1.2.641
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 +13 -0
- package/dist/addon.js +536 -461
- package/dist/addon.mjs +92 -17
- package/dist/{dist-C_XoeULr.js → ha-broker-source-D3_ZXq6l.js} +67695 -65422
- package/dist/{dist-Cvz76AD1.mjs → ha-broker-source-vytM8SXk.mjs} +67609 -65366
- package/dist/ha-export/ha-export.addon.js +209 -86
- package/dist/ha-export/ha-export.addon.mjs +164 -41
- package/i18n/en.json +2 -2
- package/i18n/it.json +2 -2
- package/package.json +1 -1
package/dist/addon.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as humiditySensorCapability, $t as array, A as brokerCapability, At as temperatureSensorCapability, Bt as DeviceRole, C as alarmPanelCapability, Ct as runningFromVacuumState, D as bestLocationMatch, Dt as smokeCapability, E as batteryCapability, F as carbonMonoxideCapability, Ft as valveCapability, G as deviceAdoptionCapability, Gt as baseUnitOf, H as controlCapability, Ht as errMsg, I as climateControlCapability, It as vibrationCapability, J as eventEmitterCapability, Jt as defineRecordKinds, Kt as createEvent, L as colorCapability, Lt as waterHeaterCapability, M as buildDeviceAdminUrl, Mt as tryConvertUnit, N as buttonCapability, Nt as updateCapability, O as binaryCapability, Ot as switchCapability, P as calendarSourceCapability, Pt as vacuumControlCapability, Q as humidifierCapability, Qt as _enum, R as connectivityCapability, Rt as weatherCapability, S as airQualitySensorCapability, St as runningFromMediaPlayer, T as automationControlCapability, Tt as scriptRunnerCapability, U as coverCapability, V as contactCapability, Vt as DeviceType, W as deviceAdminLinkCapability, Wt as RecordSecretUnavailableError, X as floodCapability, Y as fanControlCapability, Yt as entryBody, Z as gasCapability, _t as publicEndpointReaderFrom, a as BaseDevice, an as record, at as motionCapability, b as accessoriesCapability, cn as unknown, ct as notifierCapability, dt as parseAdminBase, en as boolean, et as imageCapability, ft as powerMeterCapability, ht as pressureSensorCapability, in as object, it as mediaPlayerCapability, j as buildAddonRouteProvider, jt as tryConvertDelta, k as brightnessCapability, kt as tamperCapability, ln as url, lt as numericSensorCapability, mt as presenceCapability, nn as literal, nt as lawnMowerControlCapability, o as BaseDeviceProvider, on as string, ot as normalizeUnit, p as EnumSensorDateTimeFormatSchema, pt as prepareNotification, q as enumSensorCapability, qt as defineEntryKind, rn as number, rt as lockControlCapability, sn as union, st as notificationOutputCapability, t as HA_BROKER_KIND, tn as discriminatedUnion, tt as ingestReading, un as EventCategory, v as RUNNING_STATE_COLD, vt as quantityFromUnit, w as ambientLightSensorCapability, wt as runningStateCapability, x as addonRoutesCapability, xt as runningFromLawnMower, y as TargetSchema, yt as resolveAttachmentUrls, zt as DeviceFeature } from "./ha-broker-source-vytM8SXk.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
|
|
@@ -7230,21 +7230,27 @@ function haConfigSchema() {
|
|
|
7230
7230
|
title: "Home Assistant notify",
|
|
7231
7231
|
titleKey: "provider-homeassistant:haConfig.s_connection.title",
|
|
7232
7232
|
fields: [{
|
|
7233
|
-
type: "
|
|
7233
|
+
type: "broker-select",
|
|
7234
|
+
key: "brokerId",
|
|
7235
|
+
label: "Broker",
|
|
7236
|
+
labelKey: "provider-homeassistant:haConfig.s_connection.brokerId.label",
|
|
7237
|
+
description: "The Home Assistant connection the notification goes through.",
|
|
7238
|
+
descriptionKey: "provider-homeassistant:haConfig.s_connection.brokerId.description",
|
|
7239
|
+
brokerKind: HA_BROKER_KIND
|
|
7240
|
+
}, {
|
|
7241
|
+
type: "select",
|
|
7234
7242
|
key: "service",
|
|
7235
7243
|
label: "Notify service",
|
|
7236
7244
|
labelKey: "provider-homeassistant:haConfig.s_connection.service.label",
|
|
7237
7245
|
required: true,
|
|
7246
|
+
options: [],
|
|
7238
7247
|
placeholder: "mobile_app_pixel_7",
|
|
7239
|
-
description: "
|
|
7240
|
-
descriptionKey: "provider-homeassistant:haConfig.s_connection.service.description"
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
labelKey: "provider-homeassistant:haConfig.s_connection.brokerId.label",
|
|
7246
|
-
description: "Optional; blank uses the only configured broker.",
|
|
7247
|
-
descriptionKey: "provider-homeassistant:haConfig.s_connection.brokerId.description"
|
|
7248
|
+
description: "Loaded from the broker once it is picked. If the list does not load, type the part after `notify.`.",
|
|
7249
|
+
descriptionKey: "provider-homeassistant:haConfig.s_connection.service.description",
|
|
7250
|
+
discoverOptions: {
|
|
7251
|
+
kind: HA_NOTIFICATION_KIND,
|
|
7252
|
+
dependsOn: ["brokerId"]
|
|
7253
|
+
}
|
|
7248
7254
|
}]
|
|
7249
7255
|
}] };
|
|
7250
7256
|
}
|
|
@@ -7385,24 +7391,70 @@ function buildNotifyServiceData(prepared) {
|
|
|
7385
7391
|
* `get_services` returns `{ [domain]: { [service]: {...} } }`; we read the
|
|
7386
7392
|
* `notify` domain. mobile_app_* services (rich push features) sort first.
|
|
7387
7393
|
*/
|
|
7388
|
-
function parseNotifyServices(result, brokerId) {
|
|
7394
|
+
function parseNotifyServices(result, brokerId, deviceNames) {
|
|
7389
7395
|
if (typeof result !== "object" || result === null) return [];
|
|
7390
7396
|
const notify = result["notify"];
|
|
7391
7397
|
if (typeof notify !== "object" || notify === null) return [];
|
|
7392
|
-
return [...Object.
|
|
7398
|
+
return [...Object.entries(notify)].sort(([a], [b]) => {
|
|
7393
7399
|
const am = a.startsWith("mobile_app_") ? 0 : 1;
|
|
7394
7400
|
const bm = b.startsWith("mobile_app_") ? 0 : 1;
|
|
7395
7401
|
if (am !== bm) return am - bm;
|
|
7396
7402
|
return a.localeCompare(b);
|
|
7397
|
-
}).map((service) => ({
|
|
7403
|
+
}).map(([service, definition]) => ({
|
|
7398
7404
|
kind: HA_NOTIFICATION_KIND,
|
|
7399
|
-
suggestedName:
|
|
7405
|
+
suggestedName: friendlyServiceName(service, definition, deviceNames),
|
|
7400
7406
|
config: {
|
|
7401
7407
|
service,
|
|
7402
7408
|
...brokerId !== void 0 ? { brokerId } : {}
|
|
7403
7409
|
}
|
|
7404
7410
|
}));
|
|
7405
7411
|
}
|
|
7412
|
+
function nonEmptyText(value) {
|
|
7413
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
7414
|
+
}
|
|
7415
|
+
/** `alexa_media_echo` -> `Alexa Media Echo`. */
|
|
7416
|
+
function prettifyServiceId(service) {
|
|
7417
|
+
return service.split("_").filter((word) => word.length > 0).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
7418
|
+
}
|
|
7419
|
+
/**
|
|
7420
|
+
* The name an operator recognises: the device name for a mobile app, else the
|
|
7421
|
+
* service's own `name`, else its `description`, else the prettified id.
|
|
7422
|
+
*/
|
|
7423
|
+
function friendlyServiceName(service, definition, deviceNames) {
|
|
7424
|
+
const device = deviceNames?.get(service);
|
|
7425
|
+
if (device !== void 0) return device;
|
|
7426
|
+
if (typeof definition === "object" && definition !== null) {
|
|
7427
|
+
const fields = { ...definition };
|
|
7428
|
+
const name = nonEmptyText(fields["name"]);
|
|
7429
|
+
if (name !== void 0) return name;
|
|
7430
|
+
const description = nonEmptyText(fields["description"]);
|
|
7431
|
+
if (description !== void 0) return description;
|
|
7432
|
+
}
|
|
7433
|
+
return prettifyServiceId(service);
|
|
7434
|
+
}
|
|
7435
|
+
/** HA's slug of a device name, as it appears in `mobile_app_<slug>`. */
|
|
7436
|
+
function slugifyDeviceName(name) {
|
|
7437
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
7438
|
+
}
|
|
7439
|
+
/**
|
|
7440
|
+
* `mobile_app_<slug>` -> device name, read from a `config/device_registry/list`
|
|
7441
|
+
* reply. Only devices of the mobile_app integration count; the name the user
|
|
7442
|
+
* gave wins over the one the app reported.
|
|
7443
|
+
*/
|
|
7444
|
+
function mobileAppDeviceNames(registry) {
|
|
7445
|
+
const names = /* @__PURE__ */ new Map();
|
|
7446
|
+
if (!Array.isArray(registry)) return names;
|
|
7447
|
+
for (const entry of registry) {
|
|
7448
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
7449
|
+
const device = { ...entry };
|
|
7450
|
+
const identifiers = device["identifiers"];
|
|
7451
|
+
if (!(Array.isArray(identifiers) && identifiers.some((pair) => Array.isArray(pair) && pair[0] === "mobile_app"))) continue;
|
|
7452
|
+
const name = nonEmptyText(device["name_by_user"]) ?? nonEmptyText(device["name"]);
|
|
7453
|
+
if (name === void 0) continue;
|
|
7454
|
+
names.set(`mobile_app_${slugifyDeviceName(name)}`, name);
|
|
7455
|
+
}
|
|
7456
|
+
return names;
|
|
7457
|
+
}
|
|
7406
7458
|
/**
|
|
7407
7459
|
* CRUD over the `ha-notification-targets` record kind.
|
|
7408
7460
|
*
|
|
@@ -7495,7 +7547,12 @@ function createHaNotificationOutputProvider(deps) {
|
|
|
7495
7547
|
return deps.listBrokerIds()[0] ?? null;
|
|
7496
7548
|
}
|
|
7497
7549
|
/** Degrade → build → publish. NEVER throws through the cap. */
|
|
7498
|
-
async function dispatch(target,
|
|
7550
|
+
async function dispatch(target, raw) {
|
|
7551
|
+
const notification = deps.readPublicEndpoint === void 0 ? raw : await resolveAttachmentUrls({
|
|
7552
|
+
notification: raw,
|
|
7553
|
+
readPublicEndpoint: deps.readPublicEndpoint,
|
|
7554
|
+
...logger !== void 0 ? { logger } : {}
|
|
7555
|
+
});
|
|
7499
7556
|
const prepared = prepareNotification(descriptor.caps, notification);
|
|
7500
7557
|
const service = readService(target.config);
|
|
7501
7558
|
if (!service) return {
|
|
@@ -7556,12 +7613,24 @@ function createHaNotificationOutputProvider(deps) {
|
|
|
7556
7613
|
},
|
|
7557
7614
|
discoverTargets: async ({ kind, config }) => {
|
|
7558
7615
|
if (kind !== "homeassistant") return [];
|
|
7616
|
+
const deviceNamesOf = async (brokerId) => {
|
|
7617
|
+
if (deps.listDevices === void 0) return /* @__PURE__ */ new Map();
|
|
7618
|
+
try {
|
|
7619
|
+
return mobileAppDeviceNames(await deps.listDevices(brokerId));
|
|
7620
|
+
} catch (err) {
|
|
7621
|
+
logger?.warn("ha device registry read failed; naming services from their ids", { meta: {
|
|
7622
|
+
brokerId,
|
|
7623
|
+
error: errMsg(err)
|
|
7624
|
+
} });
|
|
7625
|
+
return /* @__PURE__ */ new Map();
|
|
7626
|
+
}
|
|
7627
|
+
};
|
|
7559
7628
|
const explicit = config ? readBrokerId(config) : void 0;
|
|
7560
7629
|
const brokerIds = explicit ? [explicit] : [...deps.listBrokerIds()];
|
|
7561
7630
|
const out = [];
|
|
7562
7631
|
for (const brokerId of brokerIds) try {
|
|
7563
7632
|
const result = await deps.getServices(brokerId);
|
|
7564
|
-
out.push(...parseNotifyServices(result, brokerId));
|
|
7633
|
+
out.push(...parseNotifyServices(result, brokerId, await deviceNamesOf(brokerId)));
|
|
7565
7634
|
} catch (err) {
|
|
7566
7635
|
logger?.warn("ha get_services discovery failed", { meta: {
|
|
7567
7636
|
brokerId,
|
|
@@ -8430,7 +8499,13 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
|
|
|
8430
8499
|
if (!manager) throw new Error(`ha-broker '${brokerId}' not found`);
|
|
8431
8500
|
return manager.sendMessage({ type: "get_services" });
|
|
8432
8501
|
},
|
|
8502
|
+
listDevices: async (brokerId) => {
|
|
8503
|
+
const manager = this.requireRegistry().getManager(brokerId);
|
|
8504
|
+
if (!manager) throw new Error(`ha-broker '${brokerId}' not found`);
|
|
8505
|
+
return manager.sendMessage({ type: "config/device_registry/list" });
|
|
8506
|
+
},
|
|
8433
8507
|
listBrokerIds: () => this.activeBrokers.map((b) => b.id),
|
|
8508
|
+
readPublicEndpoint: publicEndpointReaderFrom(this.ctx.api.localNetwork),
|
|
8434
8509
|
logger: this.ctx.logger.child("notification-output")
|
|
8435
8510
|
});
|
|
8436
8511
|
}
|