zwave-js
Version:
Z-Wave driver written entirely in JavaScript/TypeScript
187 lines (186 loc) • 7.58 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var VirtualEndpoint_exports = {};
__export(VirtualEndpoint_exports, {
VirtualEndpoint: () => VirtualEndpoint
});
module.exports = __toCommonJS(VirtualEndpoint_exports);
var import_cc = require("@zwave-js/cc");
var import_core = require("@zwave-js/core");
var import_shared = require("@zwave-js/shared");
var import_arrays = require("alcalzone-shared/arrays");
var import_MultiCCAPIWrapper = require("./MultiCCAPIWrapper.js");
var import_VirtualNode = require("./VirtualNode.js");
class VirtualEndpoint {
static {
__name(this, "VirtualEndpoint");
}
driver;
index;
constructor(node, driver, index) {
this.driver = driver;
this.index = index;
if (node)
this._node = node;
}
/** Required by {@link IZWaveEndpoint} */
virtual = true;
/** The virtual node this endpoint belongs to */
_node;
get node() {
return this._node;
}
setNode(node) {
this._node = node;
}
get nodeId() {
if (this.node.id != void 0)
return this.node.id;
const ret = this.node.physicalNodes.map((n) => n.id);
if (ret.length === 1)
return ret[0];
return ret;
}
/** Tests if this endpoint supports the given CommandClass */
supportsCC(cc) {
return this.node.physicalNodes.some((n) => {
const endpoint = n.getEndpoint(this.index);
return endpoint?.supportsCC(cc);
});
}
/**
* Retrieves the minimum non-zero version of the given CommandClass the physical endpoints implement
* Returns 0 if the CC is not supported at all.
*/
getCCVersion(cc) {
const nonZeroVersions = this.node.physicalNodes.map((n) => n.getEndpoint(this.index)?.getCCVersion(cc)).filter((v) => v != void 0 && v > 0);
if (!nonZeroVersions.length)
return 0;
return Math.min(...nonZeroVersions);
}
/**
* @internal
* Creates an API instance for a given command class. Throws if no API is defined.
* @param ccId The command class to create an API instance for
*/
createAPI(ccId) {
const createCCAPI = /* @__PURE__ */ __name((endpoint, secClass) => {
if ((0, import_core.securityClassIsS2)(secClass) && endpoint.node.physicalNodes.length > 1) {
const secMan = this.driver.getSecurityManager2(endpoint.node.physicalNodes[0].id);
return import_cc.CCAPI.create(ccId, this.driver, endpoint).withOptions({
s2MulticastGroupId: secMan?.createMulticastGroup(endpoint.node.physicalNodes.map((n) => n.id), secClass)
});
} else {
return import_cc.CCAPI.create(ccId, this.driver, endpoint);
}
}, "createCCAPI");
if (this.node.hasMixedCommunicationProfiles) {
const apiInstances = [
...this.node.nodesByCommunicationProfile.entries()
].map(([profile, nodes]) => {
const node = new import_VirtualNode.VirtualNode(this.node.id, this.driver, nodes);
const endpoint = node.getEndpoint(this.index) ?? node;
const secClass = (0, import_VirtualNode.getSecurityClassFromCommunicationProfile)(profile);
return createCCAPI(endpoint, secClass);
});
return (0, import_MultiCCAPIWrapper.createMultiCCAPIWrapper)(apiInstances);
} else {
const profile = [...this.node.nodesByCommunicationProfile.keys()][0];
const securityClass = (0, import_VirtualNode.getSecurityClassFromCommunicationProfile)(profile);
return createCCAPI(this, securityClass);
}
}
_commandClassAPIs = /* @__PURE__ */ new Map();
_commandClassAPIsProxy = new Proxy(this._commandClassAPIs, {
get: /* @__PURE__ */ __name((target, ccNameOrId) => {
if (process.env.NODE_ENV === "test" && typeof ccNameOrId === "string" && (ccNameOrId === "$$typeof" || ccNameOrId === "constructor" || ccNameOrId.includes("@@__IMMUTABLE"))) {
return void 0;
}
if (typeof ccNameOrId === "symbol") {
if (ccNameOrId === Symbol.iterator) {
return this.commandClassesIterator;
} else if (ccNameOrId === Symbol.toStringTag) {
return "[object Object]";
}
return void 0;
} else {
const ccId = (0, import_cc.normalizeCCNameOrId)(ccNameOrId);
if (ccId == void 0) {
throw new import_core.ZWaveError(`Command Class ${ccNameOrId} is not implemented!`, import_core.ZWaveErrorCodes.CC_NotImplemented);
}
if (!target.has(ccId)) {
const api = this.createAPI(ccId);
target.set(ccId, api);
}
return target.get(ccId);
}
}, "get")
});
/**
* Used to iterate over the commandClasses API without throwing errors by accessing unsupported CCs
*/
commandClassesIterator = function* () {
const allCCs = (0, import_arrays.distinct)(this._node.physicalNodes.map((n) => n.getEndpoint(this.index)).filter((e) => !!e).flatMap((e) => [...e.implementedCommandClasses.keys()]));
for (const cc of allCCs) {
if (this.supportsCC(cc)) {
const APIConstructor = (0, import_cc.getAPI)(cc);
if ((0, import_shared.staticExtends)(APIConstructor, import_cc.PhysicalCCAPI))
continue;
yield this.commandClasses[cc];
}
}
}.bind(this);
/**
* Provides access to simplified APIs that are tailored to specific CCs.
* Make sure to check support of each API using `API.isSupported()` since
* all other API calls will throw if the API is not supported
*/
get commandClasses() {
return this._commandClassAPIsProxy;
}
/** Allows checking whether a CC API is supported before calling it with {@link VirtualEndpoint.invokeCCAPI} */
supportsCCAPI(cc) {
return this.commandClasses[cc].isSupported();
}
/**
* Allows dynamically calling any CC API method on this virtual endpoint by CC ID and method name.
* Use {@link VirtualEndpoint.supportsCCAPI} to check support first.
*
* **Warning:** Get-type commands are not supported, even if auto-completion indicates that they are.
*/
invokeCCAPI(cc, method, ...args) {
const CCAPI2 = this.commandClasses[cc];
const ccId = (0, import_cc.normalizeCCNameOrId)(cc);
const ccName = (0, import_core.getCCName)(ccId);
if (!CCAPI2) {
throw new import_core.ZWaveError(`The API for the ${ccName} CC does not exist or is not implemented!`, import_core.ZWaveErrorCodes.CC_NoAPI);
}
const apiMethod = CCAPI2[method];
if (typeof apiMethod !== "function") {
throw new import_core.ZWaveError(`Method "${method}" does not exist on the API for the ${ccName} CC!`, import_core.ZWaveErrorCodes.CC_NotImplemented);
}
return apiMethod.apply(CCAPI2, args);
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
VirtualEndpoint
});
//# sourceMappingURL=VirtualEndpoint.js.map