zigbee-herdsman
Version:
An open source ZigBee gateway solution with node.js.
590 lines • 28.5 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const entity_1 = __importDefault(require("./entity"));
const Zcl = __importStar(require("../../zcl"));
const zclTransactionSequenceNumber_1 = __importDefault(require("../helpers/zclTransactionSequenceNumber"));
const ZclFrameConverter = __importStar(require("../helpers/zclFrameConverter"));
const request_1 = __importDefault(require("../helpers/request"));
const requestQueue_1 = __importDefault(require("../helpers/requestQueue"));
const group_1 = __importDefault(require("./group"));
const device_1 = __importDefault(require("./device"));
const assert_1 = __importDefault(require("assert"));
const logger_1 = require("../../utils/logger");
const NS = 'zh:controller:endpoint';
class Endpoint extends entity_1.default {
deviceID;
inputClusters;
outputClusters;
profileID;
ID;
clusters;
deviceIeeeAddress;
deviceNetworkAddress;
_binds;
_configuredReportings;
meta;
pendingRequests;
// Getters/setters
get binds() {
return this._binds.map((entry) => {
let target = null;
if (entry.type === 'endpoint') {
const device = device_1.default.byIeeeAddr(entry.deviceIeeeAddress);
if (device) {
target = device.getEndpoint(entry.endpointID);
}
}
else {
target = group_1.default.byGroupID(entry.groupID);
}
if (target) {
return { target, cluster: Zcl.Utils.getCluster(entry.cluster, this.getDevice().manufacturerID) };
}
else {
return undefined;
}
}).filter(b => b !== undefined);
}
get configuredReportings() {
return this._configuredReportings.map((entry) => {
const cluster = Zcl.Utils.getCluster(entry.cluster, entry.manufacturerCode);
let attribute;
if (cluster.hasAttribute(entry.attrId)) {
attribute = cluster.getAttribute(entry.attrId);
}
else {
attribute = {
ID: entry.attrId,
name: undefined,
type: undefined,
manufacturerCode: undefined
};
}
return {
cluster, attribute,
minimumReportInterval: entry.minRepIntval,
maximumReportInterval: entry.maxRepIntval,
reportableChange: entry.repChange,
};
});
}
constructor(ID, profileID, deviceID, inputClusters, outputClusters, deviceNetworkAddress, deviceIeeeAddress, clusters, binds, configuredReportings, meta) {
super();
this.ID = ID;
this.profileID = profileID;
this.deviceID = deviceID;
this.inputClusters = inputClusters;
this.outputClusters = outputClusters;
this.deviceNetworkAddress = deviceNetworkAddress;
this.deviceIeeeAddress = deviceIeeeAddress;
this.clusters = clusters;
this._binds = binds;
this._configuredReportings = configuredReportings;
this.meta = meta;
this.pendingRequests = new requestQueue_1.default(this);
}
/**
* Get device of this endpoint
*/
getDevice() {
return device_1.default.byIeeeAddr(this.deviceIeeeAddress);
}
/**
* @param {number|string} clusterKey
* @returns {boolean}
*/
supportsInputCluster(clusterKey) {
const cluster = Zcl.Utils.getCluster(clusterKey);
return this.inputClusters.includes(cluster.ID);
}
/**
* @param {number|string} clusterKey
* @returns {boolean}
*/
supportsOutputCluster(clusterKey) {
const cluster = Zcl.Utils.getCluster(clusterKey);
return this.outputClusters.includes(cluster.ID);
}
/**
* @returns {Zcl.TsType.Cluster[]}
*/
getInputClusters() {
return this.clusterNumbersToClusters(this.inputClusters);
}
/**
* @returns {Zcl.TsType.Cluster[]}
*/
getOutputClusters() {
return this.clusterNumbersToClusters(this.outputClusters);
}
clusterNumbersToClusters(clusterNumbers) {
return clusterNumbers.map((c) => Zcl.Utils.getCluster(c, this.getDevice().manufacturerID));
}
/*
* CRUD
*/
static fromDatabaseRecord(record, deviceNetworkAddress, deviceIeeeAddress) {
// Migrate attrs to attributes
for (const entry of Object.values(record.clusters).filter((e) => e.hasOwnProperty('attrs'))) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
entry.attributes = entry.attrs;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
delete entry.attrs;
}
return new Endpoint(record.epId, record.profId, record.devId, record.inClusterList, record.outClusterList, deviceNetworkAddress, deviceIeeeAddress, record.clusters, record.binds || [], record.configuredReportings || [], record.meta || {});
}
toDatabaseRecord() {
return {
profId: this.profileID, epId: this.ID, devId: this.deviceID,
inClusterList: this.inputClusters, outClusterList: this.outputClusters, clusters: this.clusters,
binds: this._binds, configuredReportings: this._configuredReportings, meta: this.meta,
};
}
static create(ID, profileID, deviceID, inputClusters, outputClusters, deviceNetworkAddress, deviceIeeeAddress) {
return new Endpoint(ID, profileID, deviceID, inputClusters, outputClusters, deviceNetworkAddress, deviceIeeeAddress, {}, [], [], {});
}
saveClusterAttributeKeyValue(clusterKey, list) {
const cluster = Zcl.Utils.getCluster(clusterKey);
if (!this.clusters[cluster.name])
this.clusters[cluster.name] = { attributes: {} };
for (const [attribute, value] of Object.entries(list)) {
this.clusters[cluster.name].attributes[attribute] = value;
}
}
getClusterAttributeValue(clusterKey, attributeKey) {
const cluster = Zcl.Utils.getCluster(clusterKey);
const attribute = cluster.getAttribute(attributeKey);
if (this.clusters[cluster.name] && this.clusters[cluster.name].attributes) {
return this.clusters[cluster.name].attributes[attribute.name];
}
return null;
}
hasPendingRequests() {
return this.pendingRequests.size > 0;
}
async sendPendingRequests(fastPolling) {
return this.pendingRequests.send(fastPolling);
}
async sendRequest(frame, options, func = (d) => {
return entity_1.default.adapter.sendZclFrameToEndpoint(this.deviceIeeeAddress, this.deviceNetworkAddress, this.ID, d, options.timeout, options.disableResponse, options.disableRecovery, options.srcEndpoint);
}) {
const logPrefix = `Request Queue (${this.deviceIeeeAddress}/${this.ID}): `;
const request = new request_1.default(func, frame, this.getDevice().pendingRequestTimeout, options.sendPolicy);
if (request.sendPolicy !== 'bulk') {
// Check if such a request is already in the queue and remove the old one(s) if necessary
this.pendingRequests.filter(request);
}
// send without queueing if sendPolicy is 'immediate' or if the device has no timeout set
if (request.sendPolicy === 'immediate'
|| !this.getDevice().pendingRequestTimeout) {
if (this.getDevice().pendingRequestTimeout > 0) {
logger_1.logger.debug(logPrefix + `send ${frame.getCommand().name} request immediately (sendPolicy=${options.sendPolicy})`, NS);
}
return request.send();
}
// If this is a bulk message, we queue directly.
if (request.sendPolicy === 'bulk') {
logger_1.logger.debug(logPrefix + `queue request (${this.pendingRequests.size})`, NS);
return this.pendingRequests.queue(request);
}
try {
logger_1.logger.debug(logPrefix + `send request`, NS);
return await request.send();
}
catch (error) {
// If we got a failed transaction, the device is likely sleeping.
// Queue for transmission later.
logger_1.logger.debug(logPrefix + `queue request (transaction failed)`, NS);
return this.pendingRequests.queue(request);
}
}
/*
* Zigbee functions
*/
checkStatus(payload) {
const codes = Array.isArray(payload) ? payload.map((i) => i.status) : [payload.statusCode];
const invalid = codes.find((c) => c !== Zcl.Status.SUCCESS);
if (invalid)
throw new Zcl.ZclStatusError(invalid);
}
async report(clusterKey, attributes, options) {
const cluster = Zcl.Utils.getCluster(clusterKey);
const payload = [];
for (const [nameOrID, value] of Object.entries(attributes)) {
if (cluster.hasAttribute(nameOrID)) {
const attribute = cluster.getAttribute(nameOrID);
payload.push({ attrId: attribute.ID, attrData: value, dataType: attribute.type });
}
else if (!isNaN(Number(nameOrID))) {
payload.push({ attrId: Number(nameOrID), attrData: value.value, dataType: value.type });
}
else {
throw new Error(`Unknown attribute '${nameOrID}', specify either an existing attribute or a number`);
}
}
await this.zclCommand(clusterKey, "report", payload, options, attributes);
}
async write(clusterKey, attributes, options) {
const cluster = Zcl.Utils.getCluster(clusterKey);
options = this.getOptionsWithDefaults(options, true, Zcl.Direction.CLIENT_TO_SERVER, cluster.manufacturerCode);
options.manufacturerCode = this.ensureManufacturerCodeIsUniqueAndGet(cluster, Object.keys(attributes), options.manufacturerCode, 'write');
const payload = [];
for (const [nameOrID, value] of Object.entries(attributes)) {
if (cluster.hasAttribute(nameOrID)) {
const attribute = cluster.getAttribute(nameOrID);
payload.push({ attrId: attribute.ID, attrData: value, dataType: attribute.type });
}
else if (!isNaN(Number(nameOrID))) {
payload.push({ attrId: Number(nameOrID), attrData: value.value, dataType: value.type });
}
else {
throw new Error(`Unknown attribute '${nameOrID}', specify either an existing attribute or a number`);
}
}
await this.zclCommand(clusterKey, options.writeUndiv ? "writeUndiv" : "write", payload, options, attributes, true);
}
async writeResponse(clusterKey, transactionSequenceNumber, attributes, options) {
(0, assert_1.default)(!options || !options.hasOwnProperty('transactionSequenceNumber'), 'Use parameter');
const cluster = Zcl.Utils.getCluster(clusterKey);
const payload = [];
for (const [nameOrID, value] of Object.entries(attributes)) {
if (value.hasOwnProperty('status')) {
if (cluster.hasAttribute(nameOrID)) {
const attribute = cluster.getAttribute(nameOrID);
payload.push({ attrId: attribute.ID, status: value.status });
}
else if (!isNaN(Number(nameOrID))) {
payload.push({ attrId: Number(nameOrID), status: value.status });
}
else {
throw new Error(`Unknown attribute '${nameOrID}', specify either an existing attribute or a number`);
}
}
else {
throw new Error(`Missing attribute 'status'`);
}
}
await this.zclCommand(clusterKey, 'writeRsp', payload, { direction: Zcl.Direction.SERVER_TO_CLIENT, ...options, transactionSequenceNumber }, attributes);
}
async read(clusterKey, attributes, options) {
const cluster = Zcl.Utils.getCluster(clusterKey);
options = this.getOptionsWithDefaults(options, true, Zcl.Direction.CLIENT_TO_SERVER, cluster.manufacturerCode);
options.manufacturerCode = this.ensureManufacturerCodeIsUniqueAndGet(cluster, attributes, options.manufacturerCode, 'read');
const payload = [];
for (const attribute of attributes) {
payload.push({ attrId: typeof attribute === 'number' ? attribute : cluster.getAttribute(attribute).ID });
}
const result = await this.zclCommand(clusterKey, 'read', payload, options, attributes, true);
if (result) {
return ZclFrameConverter.attributeKeyValue(result.frame, this.getDevice().manufacturerID);
}
else {
return null;
}
}
async readResponse(clusterKey, transactionSequenceNumber, attributes, options) {
(0, assert_1.default)(!options || !options.hasOwnProperty('transactionSequenceNumber'), 'Use parameter');
const cluster = Zcl.Utils.getCluster(clusterKey);
const payload = [];
for (const [nameOrID, value] of Object.entries(attributes)) {
if (cluster.hasAttribute(nameOrID)) {
const attribute = cluster.getAttribute(nameOrID);
payload.push({ attrId: attribute.ID, attrData: value, dataType: attribute.type, status: 0 });
}
else if (!isNaN(Number(nameOrID))) {
payload.push({ attrId: Number(nameOrID), attrData: value.value, dataType: value.type, status: 0 });
}
else {
throw new Error(`Unknown attribute '${nameOrID}', specify either an existing attribute or a number`);
}
}
await this.zclCommand(clusterKey, 'readRsp', payload, { direction: Zcl.Direction.SERVER_TO_CLIENT, ...options, transactionSequenceNumber }, attributes);
}
addBinding(clusterKey, target) {
const cluster = Zcl.Utils.getCluster(clusterKey);
if (typeof target === 'number') {
target = group_1.default.byGroupID(target) || group_1.default.create(target);
}
if (!this.binds.find((b) => b.cluster.ID === cluster.ID && b.target === target)) {
if (target instanceof group_1.default) {
this._binds.push({ cluster: cluster.ID, groupID: target.groupID, type: 'group' });
}
else {
this._binds.push({
cluster: cluster.ID, type: 'endpoint', deviceIeeeAddress: target.deviceIeeeAddress,
endpointID: target.ID
});
}
this.save();
}
}
async bind(clusterKey, target) {
const cluster = Zcl.Utils.getCluster(clusterKey);
const type = target instanceof Endpoint ? 'endpoint' : 'group';
if (typeof target === 'number') {
target = group_1.default.byGroupID(target) || group_1.default.create(target);
}
const destinationAddress = target instanceof Endpoint ? target.deviceIeeeAddress : target.groupID;
const log = `Bind ${this.deviceIeeeAddress}/${this.ID} ${cluster.name} from ` +
`'${target instanceof Endpoint ? `${destinationAddress}/${target.ID}` : destinationAddress}'`;
logger_1.logger.debug(log, NS);
try {
await entity_1.default.adapter.bind(this.deviceNetworkAddress, this.deviceIeeeAddress, this.ID, cluster.ID, destinationAddress, type, target instanceof Endpoint ? target.ID : null);
this.addBinding(clusterKey, target);
}
catch (error) {
error.message = `${log} failed (${error.message})`;
logger_1.logger.debug(error, NS);
throw error;
}
}
save() {
this.getDevice().save();
}
async unbind(clusterKey, target) {
const cluster = Zcl.Utils.getCluster(clusterKey);
const type = target instanceof Endpoint ? 'endpoint' : 'group';
const destinationAddress = target instanceof Endpoint ? target.deviceIeeeAddress : (target instanceof group_1.default ? target.groupID : target);
const log = `Unbind ${this.deviceIeeeAddress}/${this.ID} ${cluster.name} from ` +
`'${target instanceof Endpoint ? `${destinationAddress}/${target.ID}` : destinationAddress}'`;
logger_1.logger.debug(log, NS);
try {
await entity_1.default.adapter.unbind(this.deviceNetworkAddress, this.deviceIeeeAddress, this.ID, cluster.ID, destinationAddress, type, target instanceof Endpoint ? target.ID : null);
if (typeof target === 'number' && group_1.default.byGroupID(target)) {
target = group_1.default.byGroupID(target);
}
const index = this.binds.findIndex((b) => b.cluster.ID === cluster.ID && b.target === target);
if (index !== -1) {
this._binds.splice(index, 1);
this.save();
}
}
catch (error) {
error.message = `${log} failed (${error.message})`;
logger_1.logger.debug(error, NS);
throw error;
}
}
async defaultResponse(commandID, status, clusterID, transactionSequenceNumber, options) {
(0, assert_1.default)(!options || !options.hasOwnProperty('transactionSequenceNumber'), 'Use parameter');
const payload = { cmdId: commandID, statusCode: status };
await this.zclCommand(clusterID, 'defaultRsp', payload, { direction: Zcl.Direction.SERVER_TO_CLIENT, ...options, transactionSequenceNumber });
}
async configureReporting(clusterKey, items, options) {
const cluster = Zcl.Utils.getCluster(clusterKey);
options = this.getOptionsWithDefaults(options, true, Zcl.Direction.CLIENT_TO_SERVER, cluster.manufacturerCode);
options.manufacturerCode = this.ensureManufacturerCodeIsUniqueAndGet(cluster, items, options.manufacturerCode, 'configureReporting');
const payload = items.map((item) => {
let dataType, attrId;
if (typeof item.attribute === 'object') {
dataType = item.attribute.type;
attrId = item.attribute.ID;
}
else {
/* istanbul ignore else */
if (cluster.hasAttribute(item.attribute)) {
const attribute = cluster.getAttribute(item.attribute);
dataType = attribute.type;
attrId = attribute.ID;
}
}
return {
direction: Zcl.Direction.CLIENT_TO_SERVER,
attrId, dataType,
minRepIntval: item.minimumReportInterval,
maxRepIntval: item.maximumReportInterval,
repChange: item.reportableChange,
};
});
await this.zclCommand(clusterKey, 'configReport', payload, options, items, true);
for (const e of payload) {
this._configuredReportings = this._configuredReportings.filter((c) => !(c.attrId === e.attrId && c.cluster === cluster.ID &&
(!('manufacturerCode' in c) || c.manufacturerCode === options.manufacturerCode)));
}
for (const entry of payload) {
if (entry.maxRepIntval !== 0xFFFF) {
this._configuredReportings.push({
cluster: cluster.ID, attrId: entry.attrId, minRepIntval: entry.minRepIntval,
maxRepIntval: entry.maxRepIntval, repChange: entry.repChange,
manufacturerCode: options.manufacturerCode,
});
}
}
this.save();
}
async writeStructured(clusterKey, payload, options) {
await this.zclCommand(clusterKey, 'writeStructured', payload, options);
// TODO: support `writeStructuredResponse`
}
async command(clusterKey, commandKey, payload, options) {
const result = await this.zclCommand(clusterKey, commandKey, payload, options, null, false, Zcl.FrameType.SPECIFIC);
if (result) {
return result.frame.Payload;
}
}
async commandResponse(clusterKey, commandKey, payload, options, transactionSequenceNumber) {
(0, assert_1.default)(!options || !options.hasOwnProperty('transactionSequenceNumber'), 'Use parameter');
const cluster = Zcl.Utils.getCluster(clusterKey);
const command = cluster.getCommandResponse(commandKey);
transactionSequenceNumber = transactionSequenceNumber || zclTransactionSequenceNumber_1.default.next();
options = this.getOptionsWithDefaults(options, true, Zcl.Direction.SERVER_TO_CLIENT, cluster.manufacturerCode);
const frame = Zcl.ZclFrame.create(Zcl.FrameType.SPECIFIC, options.direction, options.disableDefaultResponse, options.manufacturerCode, transactionSequenceNumber, command.name, cluster.name, payload, options.reservedBits);
const log = `CommandResponse ${this.deviceIeeeAddress}/${this.ID} ` +
`${cluster.name}.${command.name}(${JSON.stringify(payload)}, ${JSON.stringify(options)})`;
logger_1.logger.debug(log, NS);
try {
await this.sendRequest(frame, options, async (f) => {
// Broadcast Green Power responses
if (this.ID === 242) {
await entity_1.default.adapter.sendZclFrameToAll(242, f, 242);
}
else {
await entity_1.default.adapter.sendZclFrameToEndpoint(this.deviceIeeeAddress, this.deviceNetworkAddress, this.ID, f, options.timeout, options.disableResponse, options.disableRecovery, options.srcEndpoint);
}
});
}
catch (error) {
error.message = `${log} failed (${error.message})`;
logger_1.logger.debug(error, NS);
throw error;
}
}
waitForCommand(clusterKey, commandKey, transactionSequenceNumber, timeout) {
const cluster = Zcl.Utils.getCluster(clusterKey);
const command = cluster.getCommand(commandKey);
const waiter = entity_1.default.adapter.waitFor(this.deviceNetworkAddress, this.ID, Zcl.FrameType.SPECIFIC, Zcl.Direction.CLIENT_TO_SERVER, transactionSequenceNumber, cluster.ID, command.ID, timeout);
const promise = new Promise((resolve, reject) => {
waiter.promise.then((payload) => resolve({ header: payload.frame.Header, payload: payload.frame.Payload }), (error) => reject(error));
});
return { promise, cancel: waiter.cancel };
}
getOptionsWithDefaults(options, disableDefaultResponse, direction, manufacturerCode) {
const providedOptions = options || {};
return {
timeout: 10000,
disableResponse: false,
disableRecovery: false,
disableDefaultResponse,
direction,
srcEndpoint: null,
reservedBits: 0,
manufacturerCode: manufacturerCode ? manufacturerCode : null,
transactionSequenceNumber: null,
writeUndiv: false,
...providedOptions
};
}
ensureManufacturerCodeIsUniqueAndGet(cluster, attributes, fallbackManufacturerCode, caller) {
const manufacturerCodes = new Set(attributes.map((nameOrID) => {
let attributeID;
if (typeof nameOrID == 'object') {
// ConfigureReportingItem
if (typeof nameOrID.attribute !== 'object') {
attributeID = nameOrID.attribute;
}
else {
return fallbackManufacturerCode;
}
}
else {
// string || number
attributeID = nameOrID;
}
// we fall back to caller|cluster provided manufacturerCode
if (cluster.hasAttribute(attributeID)) {
const attribute = cluster.getAttribute(attributeID);
return (attribute.manufacturerCode === undefined) ?
fallbackManufacturerCode :
attribute.manufacturerCode;
}
else {
// unknown attribute, we should not fail on this here
return fallbackManufacturerCode;
}
}));
if (manufacturerCodes.size == 1) {
return manufacturerCodes.values().next().value;
}
else {
throw new Error(`Cannot have attributes with different manufacturerCode in single '${caller}' call`);
}
}
async addToGroup(group) {
await this.command('genGroups', 'add', { groupid: group.groupID, groupname: '' });
group.addMember(this);
}
/**
* Remove endpoint from a group, accepts both a Group and number as parameter.
* The number parameter type should only be used when removing from a group which is not known
* to zigbee-herdsman.
*/
async removeFromGroup(group) {
await this.command('genGroups', 'remove', { groupid: group instanceof group_1.default ? group.groupID : group });
if (group instanceof group_1.default) {
group.removeMember(this);
}
}
async removeFromAllGroups() {
await this.command('genGroups', 'removeAll', {}, { disableDefaultResponse: true });
this.removeFromAllGroupsDatabase();
}
removeFromAllGroupsDatabase() {
for (const group of group_1.default.all()) {
if (group.hasMember(this)) {
group.removeMember(this);
}
}
}
async zclCommand(clusterKey, commandKey, payload, options, logPayload, checkStatus = false, frameType = Zcl.FrameType.GLOBAL) {
const cluster = Zcl.Utils.getCluster(clusterKey);
const command = (frameType == Zcl.FrameType.GLOBAL) ? Zcl.Utils.getGlobalCommand(commandKey) : cluster.getCommand(commandKey);
const hasResponse = (frameType == Zcl.FrameType.GLOBAL) ? true : command.hasOwnProperty('response');
options = this.getOptionsWithDefaults(options, hasResponse, Zcl.Direction.CLIENT_TO_SERVER, cluster.manufacturerCode);
const frame = Zcl.ZclFrame.create(frameType, options.direction, options.disableDefaultResponse, options.manufacturerCode, options.transactionSequenceNumber ?? zclTransactionSequenceNumber_1.default.next(), command.name, cluster.name, payload, options.reservedBits);
const log = `ZCL command ${this.deviceIeeeAddress}/${this.ID} ` +
`${cluster.name}.${command.name}(${JSON.stringify((logPayload) ? logPayload : payload)}, ${JSON.stringify(options)})`;
logger_1.logger.debug(log, NS);
try {
const result = await this.sendRequest(frame, options);
if (result && checkStatus && !options.disableResponse) {
this.checkStatus(result.frame.Payload);
}
return result;
}
catch (error) {
error.message = `${log} failed (${error.message})`;
logger_1.logger.debug(error, NS);
throw error;
}
}
}
exports.default = Endpoint;
//# sourceMappingURL=endpoint.js.map