UNPKG

zigbee-herdsman

Version:

An open source Zigbee gateway solution with node.js.

244 lines 10.9 kB
"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 () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __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 }); exports.ZclFrame = void 0; const node_assert_1 = __importDefault(require("node:assert")); require("../../utils/patchBigIntSerialization"); const buffaloZcl_1 = require("./buffaloZcl"); const enums_1 = require("./definition/enums"); const status_1 = require("./definition/status"); const Utils = __importStar(require("./utils")); const zclHeader_1 = require("./zclHeader"); const zclStatusError_1 = require("./zclStatusError"); const LIST_TYPES = [ enums_1.BuffaloZclDataType.LIST_UINT8, enums_1.BuffaloZclDataType.LIST_UINT16, enums_1.BuffaloZclDataType.LIST_UINT24, enums_1.BuffaloZclDataType.LIST_UINT32, enums_1.BuffaloZclDataType.LIST_ZONEINFO, ]; class ZclFrame { header; payload; cluster; command; constructor(header, payload, cluster, command) { this.header = header; this.payload = payload; this.cluster = cluster; this.command = command; } toString() { return JSON.stringify({ header: this.header, payload: this.payload, command: this.command }); } /** * Creating */ static create(frameType, direction, disableDefaultResponse, manufacturerCode, transactionSequenceNumber, commandKey, clusterKey, payload, customClusters, reservedBits = 0) { const cluster = typeof clusterKey === "object" ? clusterKey : Utils.getCluster(clusterKey, manufacturerCode, customClusters); const command = typeof commandKey === "object" ? commandKey : frameType === enums_1.FrameType.GLOBAL ? Utils.getGlobalCommand(commandKey) : direction === enums_1.Direction.CLIENT_TO_SERVER ? Utils.getClusterCommand(cluster, commandKey) : Utils.getClusterCommandResponse(cluster, commandKey); const header = new zclHeader_1.ZclHeader({ reservedBits, frameType, direction, disableDefaultResponse, manufacturerSpecific: manufacturerCode != null }, manufacturerCode, transactionSequenceNumber, command.ID); return new ZclFrame(header, payload, cluster, command); } toBuffer() { const buffalo = new buffaloZcl_1.BuffaloZcl(Buffer.alloc(250)); this.header.write(buffalo); if (this.header.isGlobal) { this.writePayloadGlobal(buffalo); } else if (this.header.isSpecific) { this.writePayloadCluster(buffalo); } else { throw new Error(`Frametype '${this.header.frameControl.frameType}' not valid`); } return buffalo.getWritten(); } writePayloadGlobal(buffalo) { (0, node_assert_1.default)("write" in this.command); this.command.write(buffalo, this.payload); } writePayloadCluster(buffalo) { (0, node_assert_1.default)("parameters" in this.command); for (const parameter of this.command.parameters) { if (!ZclFrame.conditionsValid(parameter, this.payload, undefined)) { continue; } const paramPayload = this.payload[parameter.name]; if (paramPayload == null) { // allow parameters with MINIMUM_REMAINING_BUFFER_BYTES conditions to be omitted similar to reception logic (without the value check) // should be needed only for off-spec handling (usually around backwards-compat issues) if (parameter.conditions?.some((c) => c.type === enums_1.ParameterCondition.MINIMUM_REMAINING_BUFFER_BYTES)) { continue; } throw new Error(`Parameter '${parameter.name}' is missing`); } const valueToWrite = Utils.processParameterWrite(parameter, paramPayload); buffalo.write(parameter.type, valueToWrite, {}); } } /** * Parsing */ static fromBuffer(clusterID, header, buffer, customClusters) { if (!header) { throw new Error("Invalid ZclHeader."); } const buffalo = new buffaloZcl_1.BuffaloZcl(buffer, header.length); const cluster = Utils.getCluster(clusterID, header.manufacturerCode, customClusters); const command = header.isGlobal ? Utils.getGlobalCommand(header.commandIdentifier) : header.frameControl.direction === enums_1.Direction.CLIENT_TO_SERVER ? Utils.getClusterCommand(cluster, header.commandIdentifier) : Utils.getClusterCommandResponse(cluster, header.commandIdentifier); const payload = ZclFrame.parsePayload(header, cluster, buffalo); return new ZclFrame(header, payload, cluster, command); } static parsePayload(header, cluster, buffalo) { if (header.isGlobal) { return ZclFrame.parsePayloadGlobal(header, buffalo); } if (header.isSpecific) { return ZclFrame.parsePayloadCluster(header, cluster, buffalo); } throw new Error(`Unsupported frameType '${header.frameControl.frameType}'`); } static parsePayloadCluster(header, cluster, buffalo) { const command = header.frameControl.direction === enums_1.Direction.CLIENT_TO_SERVER ? Utils.getClusterCommand(cluster, header.commandIdentifier) : Utils.getClusterCommandResponse(cluster, header.commandIdentifier); const payload = {}; for (const parameter of command.parameters) { const options = { payload }; if (!ZclFrame.conditionsValid(parameter, payload, buffalo.getBuffer().length - buffalo.getPosition())) { continue; } if (LIST_TYPES.includes(parameter.type)) { const lengthParameter = command.parameters[command.parameters.indexOf(parameter) - 1]; const length = payload[lengthParameter.name]; if (typeof length === "number") { options.length = length; } } try { const valueToProcess = buffalo.read(parameter.type, options); payload[parameter.name] = Utils.processParameterRead(parameter, valueToProcess); } catch (error) { throw new zclStatusError_1.ZclStatusError(status_1.Status.INVALID_FIELD, `${cluster.name}:${command.name}:${parameter.name} (${error.message})`); } } return payload; } static parsePayloadGlobal(header, buffalo) { const command = Utils.getFoundationCommand(header.commandIdentifier); return command.parse(buffalo); } /** * Utils */ static conditionsValid(parameter, entry, remainingBufferBytes) { if (parameter.conditions) { for (const condition of parameter.conditions) { switch (condition.type) { case enums_1.ParameterCondition.FIELD_EQUAL: { if (condition.reversed) { if (entry[condition.field] === condition.value) { return false; } } else if (entry[condition.field] !== condition.value) { return false; } break; } case enums_1.ParameterCondition.BITMASK_SET: { if (condition.reversed) { if ((entry[condition.param] & condition.mask) === condition.mask) { return false; } } else if ((entry[condition.param] & condition.mask) !== condition.mask) { return false; } break; } case enums_1.ParameterCondition.BITFIELD_ENUM: { if (((entry[condition.param] >> condition.offset) & ((1 << condition.size) - 1)) !== condition.value) { return false; } break; } case enums_1.ParameterCondition.MINIMUM_REMAINING_BUFFER_BYTES: { if (remainingBufferBytes !== undefined && remainingBufferBytes < condition.value) { return false; } break; } case enums_1.ParameterCondition.FIELD_GT: { /*if (condition.reversed) { if (entry[condition.field] >= condition.value) { return false; } } else */ if (entry[condition.field] <= condition.value) { return false; } break; } } } } return true; } isCluster(clusterName) { return this.cluster.name === clusterName; } // List of commands is not completed, feel free to add more. isCommand(commandName) { return this.command.name === commandName; } } exports.ZclFrame = ZclFrame; //# sourceMappingURL=zclFrame.js.map