UNPKG

zigbee-herdsman

Version:

An open source ZigBee gateway solution with node.js.

289 lines 10 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getDataTypeClass = getDataTypeClass; exports.getCluster = getCluster; exports.getGlobalCommand = getGlobalCommand; exports.isClusterName = isClusterName; exports.getFoundationCommand = getFoundationCommand; exports.isFoundationDiscoverRsp = isFoundationDiscoverRsp; const cluster_1 = require("./definition/cluster"); const enums_1 = require("./definition/enums"); const foundation_1 = require("./definition/foundation"); const DATA_TYPE_CLASS_DISCRETE = [ enums_1.DataType.DATA8, enums_1.DataType.DATA16, enums_1.DataType.DATA24, enums_1.DataType.DATA32, enums_1.DataType.DATA40, enums_1.DataType.DATA48, enums_1.DataType.DATA56, enums_1.DataType.DATA64, enums_1.DataType.BOOLEAN, enums_1.DataType.BITMAP8, enums_1.DataType.BITMAP16, enums_1.DataType.BITMAP24, enums_1.DataType.BITMAP32, enums_1.DataType.BITMAP40, enums_1.DataType.BITMAP48, enums_1.DataType.BITMAP56, enums_1.DataType.BITMAP64, enums_1.DataType.ENUM8, enums_1.DataType.ENUM16, enums_1.DataType.OCTET_STR, enums_1.DataType.CHAR_STR, enums_1.DataType.LONG_OCTET_STR, enums_1.DataType.LONG_CHAR_STR, enums_1.DataType.ARRAY, enums_1.DataType.STRUCT, enums_1.DataType.SET, enums_1.DataType.BAG, enums_1.DataType.CLUSTER_ID, enums_1.DataType.ATTR_ID, enums_1.DataType.BAC_OID, enums_1.DataType.IEEE_ADDR, enums_1.DataType.SEC_KEY, ]; const DATA_TYPE_CLASS_ANALOG = [ enums_1.DataType.UINT8, enums_1.DataType.UINT16, enums_1.DataType.UINT24, enums_1.DataType.UINT32, enums_1.DataType.UINT40, enums_1.DataType.UINT48, enums_1.DataType.UINT56, enums_1.DataType.INT8, enums_1.DataType.INT16, enums_1.DataType.INT24, enums_1.DataType.INT32, enums_1.DataType.INT40, enums_1.DataType.INT48, enums_1.DataType.INT56, enums_1.DataType.SEMI_PREC, enums_1.DataType.SINGLE_PREC, enums_1.DataType.DOUBLE_PREC, enums_1.DataType.TOD, enums_1.DataType.DATE, enums_1.DataType.UTC, ]; const FOUNDATION_DISCOVER_RSP_IDS = [ foundation_1.Foundation.discoverRsp.ID, foundation_1.Foundation.discoverCommandsRsp.ID, foundation_1.Foundation.discoverCommandsGenRsp.ID, foundation_1.Foundation.discoverExtRsp.ID, ]; function getDataTypeClass(dataType) { if (DATA_TYPE_CLASS_DISCRETE.includes(dataType)) { return enums_1.DataTypeClass.DISCRETE; } if (DATA_TYPE_CLASS_ANALOG.includes(dataType)) { return enums_1.DataTypeClass.ANALOG; } throw new Error(`Don't know value type for '${enums_1.DataType[dataType]}'`); } function hasCustomClusters(customClusters) { // XXX: was there a good reason to not set the parameter `customClusters` optional? it would allow simple undefined check // below is twice faster than checking `Object.keys(customClusters).length` // biome-ignore lint/style/useNamingConvention: not working properly for (const _k in customClusters) return true; return false; } function findClusterNameByID(id, manufacturerCode, clusters) { let name; // if manufacturer code is given, consider partial match if didn't match against manufacturer code let partialMatch = Boolean(manufacturerCode); for (const clusterName in clusters) { const cluster = clusters[clusterName]; if (cluster.ID === id) { // priority on first match when matching only ID if (name === undefined) { name = clusterName; } if (manufacturerCode && cluster.manufacturerCode === manufacturerCode) { name = clusterName; partialMatch = false; break; } if (!cluster.manufacturerCode) { name = clusterName; break; } } } return [name, partialMatch]; } function getClusterDefinition(key, manufacturerCode, customClusters) { let name; if (typeof key === "number") { let partialMatch; // custom clusters have priority over Zcl clusters, except in case of better match (see below) [name, partialMatch] = findClusterNameByID(key, manufacturerCode, customClusters); if (!name) { [name, partialMatch] = findClusterNameByID(key, manufacturerCode, cluster_1.Clusters); } else if (partialMatch) { let zclName; [zclName, partialMatch] = findClusterNameByID(key, manufacturerCode, cluster_1.Clusters); // Zcl clusters contain a better match, use that one if (zclName !== undefined && !partialMatch) { name = zclName; } } } else { name = key; } let cluster = name !== undefined && hasCustomClusters(customClusters) ? { ...cluster_1.Clusters[name], ...customClusters[name], // should override Zcl clusters } : cluster_1.Clusters[name]; if (!cluster) { if (typeof key === "number") { name = key.toString(); cluster = { attributes: {}, commands: {}, commandsResponse: {}, manufacturerCode: undefined, ID: key }; } else { name = undefined; } } if (!name) { throw new Error(`Cluster with name '${key}' does not exist`); } return { name, cluster }; } function createCluster(name, cluster, manufacturerCode) { const attributes = Object.assign({}, ...Object.entries(cluster.attributes).map(([k, v]) => ({ [k]: { ...v, name: k } }))); const commands = Object.assign({}, ...Object.entries(cluster.commands).map(([k, v]) => ({ [k]: { ...v, name: k } }))); const commandsResponse = Object.assign({}, ...Object.entries(cluster.commandsResponse).map(([k, v]) => ({ [k]: { ...v, name: k } }))); const getAttributeInternal = (key) => { if (typeof key === "number") { let partialMatchAttr; for (const attrKey in attributes) { const attr = attributes[attrKey]; if (attr.ID === key) { if (manufacturerCode && attr.manufacturerCode === manufacturerCode) { return attr; } if (attr.manufacturerCode === undefined) { partialMatchAttr = attr; } } } return partialMatchAttr; } for (const attrKey in attributes) { const attr = attributes[attrKey]; if (attr.name === key) { return attr; } } return undefined; }; const getAttribute = (key) => { const result = getAttributeInternal(key); if (!result) { throw new Error(`Cluster '${name}' has no attribute '${key}'`); } return result; }; const hasAttribute = (key) => { const result = getAttributeInternal(key); return !!result; }; const getCommand = (key) => { if (typeof key === "number") { for (const cmdKey in commands) { const cmd = commands[cmdKey]; if (cmd.ID === key) { return cmd; } } } else { for (const cmdKey in commands) { const cmd = commands[cmdKey]; if (cmd.name === key) { return cmd; } } } throw new Error(`Cluster '${name}' has no command '${key}'`); }; const getCommandResponse = (key) => { if (typeof key === "number") { for (const cmdKey in commandsResponse) { const cmd = commandsResponse[cmdKey]; if (cmd.ID === key) { return cmd; } } } else { for (const cmdKey in commandsResponse) { const cmd = commandsResponse[cmdKey]; if (cmd.name === key) { return cmd; } } } throw new Error(`Cluster '${name}' has no command response '${key}'`); }; return { ID: cluster.ID, attributes, manufacturerCode: cluster.manufacturerCode, name, commands, commandsResponse, getAttribute, hasAttribute, getCommand, getCommandResponse, }; } function getCluster(key, manufacturerCode, customClusters) { const { name, cluster } = getClusterDefinition(key, manufacturerCode, customClusters); return createCluster(name, cluster, manufacturerCode); } function getGlobalCommandNameById(id) { for (const commandName in foundation_1.Foundation) { if (foundation_1.Foundation[commandName].ID === id) { return commandName; } } throw new Error(`Global command with id '${id}' does not exist.`); } function getGlobalCommand(key) { const name = typeof key === "number" ? getGlobalCommandNameById(key) : key; const command = foundation_1.Foundation[name]; if (!command) { throw new Error(`Global command with key '${key}' does not exist`); } const result = { ID: command.ID, name, parameters: command.parameters, }; if (command.response !== undefined) { result.response = command.response; } return result; } function isClusterName(name) { return name in cluster_1.Clusters; } function getFoundationCommand(id) { for (const commandName in foundation_1.Foundation) { const command = foundation_1.Foundation[commandName]; if (command.ID === id) { return command; } } throw new Error(`Foundation command '${id}' does not exist.`); } function isFoundationDiscoverRsp(id) { return FOUNDATION_DISCOVER_RSP_IDS.includes(id); } //# sourceMappingURL=utils.js.map