UNPKG

zigbee-herdsman-converters

Version:

Collection of device converters to be used with zigbee-herdsman

773 lines (771 loc) 29.6 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; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.generateDefinition = generateDefinition; exports.generateGreenPowerDefinition = generateGreenPowerDefinition; const zigbee_herdsman_1 = require("zigbee-herdsman"); const logger_1 = require("./logger"); const m = __importStar(require("./modernExtend")); const philips = __importStar(require("./philips")); const utils_1 = require("./utils"); const NS = "zhc:gendef"; // Generator allows to define instances of GeneratedExtend that have typed arguments to extender. class ExtendGenerator { extend; args; source; lib; constructor(args) { this.extend = args.extend; this.args = args.args; this.source = args.source; this.lib = args.lib; } getExtend() { return this.extend(this.args); } getSource() { let jsonArgs = JSON.stringify(this.args); if (!this.args || jsonArgs === "{}") { jsonArgs = ""; } return `${this.source}(${jsonArgs})`; } } // If generator will have endpoint argument - generator implementation // should not provide it if only the first device endpoint is passed in. // If multiple endpoints provided(maybe including the first device endpoint) - // they all should be passed as an argument, where possible, to be explicit. const INPUT_EXTENDERS = [ [ ["msTemperatureMeasurement"], async (d, eps) => [new ExtendGenerator({ extend: m.temperature, args: maybeEndpointArgs(d, eps), source: "temperature" })], ], [["msPressureMeasurement"], async (d, eps) => [new ExtendGenerator({ extend: m.pressure, args: maybeEndpointArgs(d, eps), source: "pressure" })]], [["msRelativeHumidity"], async (d, eps) => [new ExtendGenerator({ extend: m.humidity, args: maybeEndpointArgs(d, eps), source: "humidity" })]], [["msCO2"], async (d, eps) => [new ExtendGenerator({ extend: m.co2, args: maybeEndpointArgs(d, eps), source: "co2" })]], [["genPowerCfg"], async (d, eps) => [new ExtendGenerator({ extend: m.battery, source: "battery" })]], [["genOnOff", "genLevelCtrl", "lightingColorCtrl"], extenderOnOffLight], [["seMetering", "haElectricalMeasurement"], extenderElectricityMeter], [["closuresDoorLock"], extenderLock], [ ["msIlluminanceMeasurement"], async (d, eps) => [new ExtendGenerator({ extend: m.illuminance, args: maybeEndpointArgs(d, eps), source: "illuminance" })], ], [["msOccupancySensing"], async (d, eps) => [new ExtendGenerator({ extend: m.occupancy, source: "occupancy" })]], [ ["ssIasZone"], async (d, eps) => [ new ExtendGenerator({ extend: m.iasZoneAlarm, args: { zoneType: "generic", zoneAttributes: ["alarm_1", "alarm_2", "tamper", "battery_low"], }, source: "iasZoneAlarm", }), ], ], [["ssIasWd"], async (d, eps) => [new ExtendGenerator({ extend: m.iasWarning, source: "iasWarning" })]], [ ["genDeviceTempCfg"], async (d, eps) => [new ExtendGenerator({ extend: m.deviceTemperature, args: maybeEndpointArgs(d, eps), source: "deviceTemperature" })], ], [["pm25Measurement"], async (d, eps) => [new ExtendGenerator({ extend: m.pm25, args: maybeEndpointArgs(d, eps), source: "pm25" })]], [["msFlowMeasurement"], async (d, eps) => [new ExtendGenerator({ extend: m.flow, args: maybeEndpointArgs(d, eps), source: "flow" })]], [["msSoilMoisture"], async (d, eps) => [new ExtendGenerator({ extend: m.soilMoisture, args: maybeEndpointArgs(d, eps), source: "soilMoisture" })]], [ ["closuresWindowCovering"], async (d, eps) => [new ExtendGenerator({ extend: m.windowCovering, args: { controls: ["lift", "tilt"] }, source: "windowCovering" })], ], [["genBinaryInput"], extenderBinaryInput], [["genBinaryOutput"], extenderBinaryOutput], [["genAnalogInput"], extenderAnalogInput], [["genAnalogOutput"], extenderAnalogOutput], ]; const OUTPUT_EXTENDERS = [ [["genOnOff"], async (d, eps) => [new ExtendGenerator({ extend: m.commandsOnOff, args: maybeEndpointArgs(d, eps), source: "commandsOnOff" })]], [ ["genLevelCtrl"], async (d, eps) => [new ExtendGenerator({ extend: m.commandsLevelCtrl, args: maybeEndpointArgs(d, eps), source: "commandsLevelCtrl" })], ], [ ["lightingColorCtrl"], async (d, eps) => [new ExtendGenerator({ extend: m.commandsColorCtrl, args: maybeEndpointArgs(d, eps), source: "commandsColorCtrl" })], ], [ ["closuresWindowCovering"], async (d, eps) => [ new ExtendGenerator({ extend: m.commandsWindowCovering, args: maybeEndpointArgs(d, eps), source: "commandsWindowCovering" }), ], ], ]; function generateSource(definition, generatedExtend) { const imports = [...new Set(generatedExtend.map((e) => e.lib ?? "modernExtend"))]; const importsStr = imports.map((e) => `import * as ${e === "modernExtend" ? "m" : e} from 'zigbee-herdsman-converters/lib/${e}';`).join("\n"); const meta = definition.meta ? `\n meta: ${JSON.stringify(definition.meta)},` : ""; return `${importsStr} export default { zigbeeModel: ['${definition.zigbeeModel}'], model: '${definition.model}', vendor: '${definition.vendor}', description: 'Automatically generated definition', extend: [${generatedExtend.map((e) => `${e.lib ?? "m"}.${e.getSource()}`).join(", ")}],${meta} }; `; } function generateGreenPowerSource(definition, ieeeAddr) { return `import {genericGreenPower} from 'zigbee-herdsman-converters/lib/modernExtend'; export default { fingerprint: [{modelID: '${definition.model}', ieeeAddr: new RegExp('^${ieeeAddr}$')}], model: '${definition.model}', vendor: '${definition.vendor}', description: 'Automatically generated definition for Green Power', extend: [genericGreenPower()], };`; } async function generateDefinition(device) { if (device.type === "GreenPower") { return generateGreenPowerDefinition(device); } // Map cluster to all endpoints that have this cluster. const mapClusters = (endpoint, clusters, clusterMap) => { for (const cluster of clusters) { if (!clusterMap.has(cluster.name)) { clusterMap.set(cluster.name, []); } const endpointsWithCluster = clusterMap.get(cluster.name); endpointsWithCluster.push(endpoint); } }; const knownInputClusters = INPUT_EXTENDERS.flatMap((ext) => ext[0]); const knownOutputClusters = OUTPUT_EXTENDERS.flatMap((ext) => ext[0]); const inputClusterMap = new Map(); const outputClusterMap = new Map(); for (const endpoint of device.endpoints) { // Filter clusters to leave only the ones that we can generate extenders for. const inputClusters = endpoint.getInputClusters().filter((c) => knownInputClusters.find((known) => known === c.name)); const outputClusters = endpoint.getOutputClusters().filter((c) => knownOutputClusters.find((known) => known === c.name)); mapClusters(endpoint, inputClusters, inputClusterMap); mapClusters(endpoint, outputClusters, outputClusterMap); } // Generate extenders const usedExtenders = []; const generatedExtend = []; const addGenerators = async (clusterName, endpoints, extenders) => { const extender = extenders.find((e) => e[0].includes(clusterName)); if (!extender || usedExtenders.includes(extender)) { return; } usedExtenders.push(extender); generatedExtend.push(...(await extender[1](device, endpoints))); }; for (const [cluster, endpoints] of inputClusterMap) { await addGenerators(cluster, endpoints, INPUT_EXTENDERS); } for (const [cluster, endpoints] of outputClusterMap) { await addGenerators(cluster, endpoints, OUTPUT_EXTENDERS); } const extenders = generatedExtend.map((e) => e.getExtend()); // Generated definition below will provide this. for (const extender of extenders) { extender.endpoint = undefined; } // Currently multiEndpoint is enabled if device has more then 1 endpoint. // It is possible to better check if device should be considered multiEndpoint // based, for example, on generator arguments(i.e. presence of "endpointNames"), // but this will be enough for now. const endpointsWithoutGreenPower = device.endpoints.filter((e) => e.ID !== 242); const multiEndpoint = endpointsWithoutGreenPower.length > 1; if (multiEndpoint) { const endpoints = {}; for (const endpoint of endpointsWithoutGreenPower) { endpoints[endpoint.ID.toString()] = endpoint.ID; } // Add to beginning for better visibility. generatedExtend.unshift(new ExtendGenerator({ extend: m.deviceEndpoints, args: { endpoints }, source: "deviceEndpoints" })); extenders.unshift(generatedExtend[0].getExtend()); } const definition = { zigbeeModel: [device.modelID], model: device.modelID ?? "", vendor: device.manufacturerName ?? "", description: "Automatically generated definition", extend: extenders, generated: true, }; const externalDefinitionSource = generateSource(definition, generatedExtend); return { externalDefinitionSource, definition }; } function generateGreenPowerDefinition(device) { const definition = { fingerprint: [{ modelID: device.modelID, ieeeAddr: new RegExp(`^${device.ieeeAddr}$`) }], model: device.modelID ?? "", vendor: device.manufacturerName ?? "", description: "Automatically generated definition for Green Power", extend: [m.genericGreenPower()], generated: true, }; const externalDefinitionSource = generateGreenPowerSource(definition, device.ieeeAddr); return { externalDefinitionSource, definition }; } function stringifyEps(endpoints) { return endpoints.map((e) => e.ID.toString()); } // This function checks if provided array of endpoints contain // only first device endpoint, which is passed in as `firstEndpoint`. function onlyFirstDeviceEnpoint(device, endpoints) { return endpoints.length === 1 && endpoints[0].ID === device.endpoints[0].ID; } // maybeEndpoints returns either `toExtend` if only first device endpoint is provided // as `endpoints`, or `endpointNames` with `toExtend`. // This allows to drop unnecessary `endpointNames` argument if it is not needed. function maybeEndpointArgs(device, endpoints, toExtend) { if (onlyFirstDeviceEnpoint(device, endpoints)) { return toExtend; } return { endpointNames: stringifyEps(endpoints), ...toExtend }; } async function extenderLock(device, endpoints) { // TODO: Support multiple endpoints if (endpoints.length > 1) { logger_1.logger.warning("extenderLock can accept only one endpoint", NS); } const endpoint = endpoints[0]; const pinCodeCount = await (0, utils_1.getClusterAttributeValue)(endpoint, "closuresDoorLock", "numOfPinUsersSupported", 50); return [new ExtendGenerator({ extend: m.lock, args: { pinCodeCount }, source: "lock" })]; } async function extenderOnOffLight(device, endpoints) { const generated = []; const lightEndpoints = endpoints.filter((e) => e.supportsInputCluster("lightingColorCtrl") || e.supportsInputCluster("genLevelCtrl")); const onOffEndpoints = endpoints.filter((e) => lightEndpoints.findIndex((ep) => e.ID === ep.ID) === -1); if (onOffEndpoints.length !== 0) { let endpointNames; if (!onlyFirstDeviceEnpoint(device, onOffEndpoints)) { endpointNames = onOffEndpoints.map((e) => e.ID.toString()); } generated.push(new ExtendGenerator({ extend: m.onOff, args: { powerOnBehavior: false, endpointNames }, source: "onOff" })); } for (const endpoint of lightEndpoints) { let endpointNames; if (!onlyFirstDeviceEnpoint(device, lightEndpoints)) { endpointNames = lightEndpoints.map((e) => e.ID.toString()); } // In case read fails, support all features with 31 let colorCapabilities = 0; if (endpoint.supportsInputCluster("lightingColorCtrl")) { colorCapabilities = await (0, utils_1.getClusterAttributeValue)(endpoint, "lightingColorCtrl", "colorCapabilities", 31); } const supportsHueSaturation = (colorCapabilities & (1 << 0)) > 0; const supportsEnhancedHueSaturation = (colorCapabilities & (1 << 1)) > 0; const supportsColorXY = (colorCapabilities & (1 << 3)) > 0; const supportsColorTemperature = (colorCapabilities & (1 << 4)) > 0; const args = {}; args.endpointNames = endpointNames; if (supportsColorTemperature) { const minColorTemp = await (0, utils_1.getClusterAttributeValue)(endpoint, "lightingColorCtrl", "colorTempPhysicalMin", 150); const maxColorTemp = await (0, utils_1.getClusterAttributeValue)(endpoint, "lightingColorCtrl", "colorTempPhysicalMax", 500); args.colorTemp = { range: [minColorTemp, maxColorTemp] }; } if (supportsColorXY) { args.color = true; if (supportsHueSaturation || supportsEnhancedHueSaturation) { args.color = {}; if (supportsHueSaturation) args.color.modes = ["xy", "hs"]; if (supportsEnhancedHueSaturation) args.color.enhancedHue = true; } } if (endpoint.getDevice().manufacturerID === zigbee_herdsman_1.Zcl.ManufacturerCode.SIGNIFY_NETHERLANDS_B_V) { generated.push(new ExtendGenerator({ extend: philips.m.light, args, source: "m.light", lib: "philips" })); } else { generated.push(new ExtendGenerator({ extend: m.light, args, source: "light" })); } } return generated; } async function extenderElectricityMeter(device, endpoints) { // TODO: Support multiple endpoints if (endpoints.length > 1) { logger_1.logger.warning("extenderElectricityMeter can accept only one endpoint", NS); } const endpoint = endpoints[0]; const metering = endpoint.supportsInputCluster("seMetering"); const electricalMeasurements = endpoint.supportsInputCluster("haElectricalMeasurement"); const args = {}; if (!metering || !electricalMeasurements) { args.cluster = metering ? "metering" : "electrical"; } if (args.cluster === "electrical") { // If this value will be 0 then the value of 'args.electricalMeasurementType' will not be changed. const measurementType = await (0, utils_1.getClusterAttributeValue)(endpoint, "haElectricalMeasurement", "measurementType", 0); // MeasurementType will have bit on index 6 set for DC measurement. const isDCMeasureType = ((measurementType >> 6) & 1) === 1; args.electricalMeasurementType = "ac"; if (isDCMeasureType) { args.electricalMeasurementType = "dc"; } } if (endpoint.ID !== 1) { args.endpointNames = stringifyEps([endpoint]); } return [new ExtendGenerator({ extend: m.electricityMeter, args, source: "electricityMeter" })]; } async function extenderBinaryInput(device, endpoints) { const generated = []; let endpointName; for (const endpoint of endpoints) { if (!onlyFirstDeviceEnpoint(device, endpoints)) { endpointName = endpoint.ID.toString(); } const name = await (0, utils_1.getClusterAttributeValue)(endpoint, "genBinaryInput", "description", endpointName ? "binary_input" : `binary_input_${endpoint.ID}`); let label; if (name !== "binary_input" && name !== `binary_input_${endpoint.ID}`) { label = name; } const description = `Binary Input ${name} on endpoint ${endpoint.ID}`; const args = { name: name.replace(/\s+/g, "_").toLowerCase(), label, cluster: "genBinaryInput", attribute: "presentValue", reporting: { min: "MIN", max: "MAX", change: 1 }, valueOn: ["ON", 1], valueOff: ["OFF", 0], description: description, access: "STATE_GET", endpointName, }; generated.push(new ExtendGenerator({ extend: m.binary, args, source: "binary" })); } return generated; } async function extenderBinaryOutput(device, endpoints) { const generated = []; let endpointName; for (const endpoint of endpoints) { if (!onlyFirstDeviceEnpoint(device, endpoints)) { endpointName = endpoint.ID.toString(); } const name = await (0, utils_1.getClusterAttributeValue)(endpoint, "genBinaryOutput", "description", endpointName ? "binary_output" : `binary_output_${endpoint.ID}`); let label; if (name !== "binary_output" && name !== `binary_output_${endpoint.ID}`) { label = name; } const description = `Binary Output ${name} on endpoint ${endpoint.ID}`; const args = { name: name.replace(/\s+/g, "_").toLowerCase(), label, cluster: "genBinaryOutput", attribute: "presentValue", reporting: { min: "MIN", max: "MAX", change: 1 }, valueOn: ["ON", 1], valueOff: ["OFF", 0], description: description, access: "ALL", endpointName, }; generated.push(new ExtendGenerator({ extend: m.binary, args, source: "binary" })); } return generated; } function getUnitfromApplicationType(applicationType) { // Map of applicationType to unit strings. Only take type ( Bits 16 to 23 ) into account. const type = (applicationType >> 16) & 0xff; const applicationTypeMap = { 0: "°C", // Temp_Degrees_C 1: "%", // Relative_Humidity_Percent 2: "Pa", // Pressure_Pascal 3: "L/s", // Flow_Liters_Per_Sec 4: "%", // Percentage 5: "ppm", // Parts_Per_Million 6: "rpm", // Rotational_Speed_RPM 7: "A", // Current_Amps 8: "Hz", // Frequency_Hz 9: "W", // Power_Watts 10: "kW", // Power_Kilo_Watts 11: "kWh", // Energy_Kilo_Watt_Hours 12: undefined, // Count 13: "kJ/kg", // Enthalpy_KJoules_Per_Kg 14: "s", // Time_Seconds }; return applicationTypeMap[type]; } function getUnitfromBACnetUnit(bacnetUnit) { const bacnetUnitMap = { 0: "m²", 1: "ft²", 2: "mA", 3: "A", 4: "Ω", 5: "V", 6: "kV", 7: "MV", 8: "VA", 9: "kVA", 10: "MVA", 11: "var", 12: "kvar", 13: "Mvar", 14: "°phase", 15: "pf", 16: "J", 17: "kJ", 18: "Wh", 19: "kWh", 20: "Btu", 21: "therm", 22: "ton·h", 23: "J/kg", 24: "Btu/lb", 25: "cycles/h", 26: "cycles/min", 27: "Hz", 28: "g/kg", 29: "%", 30: "mm", 31: "m", 32: "in", 33: "ft", 34: "W/ft²", 35: "W/m²", 36: "lm", 37: "lx", 38: "fc", 39: "kg", 40: "lb", 41: "tons", 42: "kg/s", 43: "kg/min", 44: "kg/h", 45: "lb/min", 46: "lb/h", 47: "W", 48: "kW", 49: "MW", 50: "Btu/h", 51: "hp", 52: "ton", 53: "Pa", 54: "kPa", 55: "bar", 56: "psi", 57: "cm H₂O", 58: "in H₂O", 59: "mmHg", 60: "cm Hg", 61: "in Hg", 62: "°C", 63: "K", 64: "°F", 65: "°C·d", 66: "°F·d", 67: "years", 68: "months", 69: "weeks", 70: "days", 71: "hours", 72: "minutes", 73: "seconds", 74: "m/s", 75: "km/h", 76: "ft/s", 77: "ft/min", 78: "mph", 79: "ft³", 80: "m³", 81: "imp gal", 82: "L", 83: "gal", 84: "ft³/min", 85: "m³/s", 86: "imp gal/min", 87: "L/s", 88: "L/min", 89: "gal/min", 90: "°", 91: "°C/h", 92: "°C/min", 93: "°F/h", 94: "°F/min", 95: undefined, 96: "ppm", 97: "ppb", 98: "%", 99: "%/s", 100: "1/min", 101: "1/s", 102: "psi/°F", 103: "rad", 104: "rpm", 105: "currency", 106: "currency", 107: "currency", 108: "currency", 109: "currency", 110: "currency", 111: "currency", 112: "currency", 113: "currency", 114: "currency", 115: "in²", 116: "cm²", 117: "Btu/lb", 118: "cm", 119: "lb/s", 120: "Δ°F", 121: "ΔK", 122: "kΩ", 123: "MΩ", 124: "mV", 125: "kJ/kg", 126: "MJ", 127: "J/K", 128: "J/(kg·K)", 129: "kHz", 130: "MHz", 131: "1/h", 132: "mW", 133: "hPa", 134: "mbar", 135: "m³/h", 136: "L/h", 137: "kWh/m²", 138: "kWh/ft²", 139: "MJ/m²", 140: "MJ/ft²", 141: "W/(m²·K)", 142: "ft³/s", 143: "% obscuration/ft", 144: "% obscuration/m", 145: "mΩ", 146: "MWh", 147: "kBtu", 148: "MBtu", 149: "kJ/kg_dry", 150: "MJ/kg_dry", 151: "kJ/K", 152: "MJ/K", 153: "N", 154: "g/s", 155: "g/min", 156: "tons/h", 157: "kBtu/h", 158: "1/100 s", 159: "ms", 160: "N·m", 161: "mm/s", 162: "mm/min", 163: "m/min", 164: "m/h", 165: "m³/min", 166: "m/s²", 167: "A/m", 168: "A/m²", 169: "A·m²", 170: "F", 171: "H", 172: "Ω·m", 174: "S/m", 175: "T", 176: "V/K", 177: "V/m", 178: "Wb", 179: "cd", 180: "cd/m²", 181: "K/h", 182: "K/min", 183: "J·s", 184: "rad/s", 185: "m²/N", 186: "kg/m³", 187: "N·s", 188: "N/m", 189: "W/(m·K)", 190: "µS/cm", 191: "ft³/h", 192: "gal/h", 193: "km", 194: "µm", 195: "g", 196: "mg", 197: "mL", 198: "mL/s", 199: "dB", 200: "dBm", 201: "dBV", 202: "mS/cm", 203: "var·h", 204: "kvar·h", 205: "Mvar·h", 206: "mm H₂O", 207: "‰", 208: "g/g", 209: "kg/kg", 210: "g/kg", 211: "mg/g", 212: "mg/kg", 213: "g/mL", 214: "g/L", 215: "mg/L", 216: "µg/L", 217: "g/m³", 218: "mg/m³", 219: "µg/m³", 220: "ng/m³", 221: "g/cm³", 222: "Bq", 223: "kBq", 224: "MBq", 225: "Gy", 226: "mGy", 227: "µGy", 228: "Sv", 229: "mSv", 230: "µSv", 231: "µSv/h", 232: "dBA", 233: "NTU", 234: "pH", 235: "g/m²", 236: "min/K", 237: "Ω·m²/m", 238: "A·s", 239: "VA·h", 240: "kVA·h", 241: "MVA·h", 242: "var·h", 243: "kvar·h", 244: "Mvar·h", 245: "V²·h", 246: "A²·h", 247: "J/h", 248: "ft³/d", 249: "m³/d", 250: "Wh/m³", 251: "J/m³", 252: "mol%", 253: "Pa·s", 254: "MMSCFM", }; return bacnetUnitMap[bacnetUnit]; } async function extenderAnalogInput(device, endpoints) { const generated = []; let endpointNames; for (const endpoint of endpoints) { if (!onlyFirstDeviceEnpoint(device, endpoints)) { endpointNames = [endpoint.ID.toString()]; } const name = await (0, utils_1.getClusterAttributeValue)(endpoint, "genAnalogInput", "description", endpointNames ? "analog_input" : `analog_input_${endpoint.ID}`); let label; if (name !== "analog_input" && name !== `analog_input_${endpoint.ID}`) { label = name; } const description = `Analog Input ${name} on endpoint ${endpoint.ID}`; const applicationType = await (0, utils_1.getClusterAttributeValue)(endpoint, "genAnalogInput", "applicationType", undefined); let unit; if (applicationType !== undefined) { unit = getUnitfromApplicationType(applicationType); } if (unit === undefined) { const bacnet_unit = await (0, utils_1.getClusterAttributeValue)(endpoint, "genAnalogInput", "engineeringUnits", undefined); if (bacnet_unit !== undefined) { unit = getUnitfromBACnetUnit(bacnet_unit); } } const args = { name: name.replace(/\s+/g, "_").toLowerCase(), label, valueMin: await (0, utils_1.getClusterAttributeValue)(endpoint, "genAnalogInput", "minPresentValue", undefined), valueMax: await (0, utils_1.getClusterAttributeValue)(endpoint, "genAnalogInput", "maxPresentValue", undefined), valueStep: await (0, utils_1.getClusterAttributeValue)(endpoint, "genAnalogInput", "resolution", undefined), cluster: "genAnalogInput", attribute: "presentValue", reporting: { min: "MIN", max: "MAX", change: 1 }, description: description, access: "STATE_GET", endpointNames, unit, }; generated.push(new ExtendGenerator({ extend: m.numeric, args, source: "numeric" })); } return generated; } async function extenderAnalogOutput(device, endpoints) { const generated = []; let endpointNames; for (const endpoint of endpoints) { if (!onlyFirstDeviceEnpoint(device, endpoints)) { endpointNames = [endpoint.ID.toString()]; } const name = await (0, utils_1.getClusterAttributeValue)(endpoint, "genAnalogOutput", "description", endpointNames ? "analog_output" : `analog_output_${endpoint.ID}`); let label; if (name !== "analog_output" && name !== `analog_output_${endpoint.ID}`) { label = name; } const description = `Analog Output ${name} on endpoint ${endpoint.ID}`; const applicationType = await (0, utils_1.getClusterAttributeValue)(endpoint, "genAnalogOutput", "applicationType", undefined); let unit; if (applicationType !== undefined) { unit = getUnitfromApplicationType(applicationType); } if (unit === undefined) { const bacnet_unit = await (0, utils_1.getClusterAttributeValue)(endpoint, "genAnalogOutput", "engineeringUnits", undefined); if (bacnet_unit !== undefined) { unit = getUnitfromBACnetUnit(bacnet_unit); } } const args = { name: name.replace(/\s+/g, "_").toLowerCase(), label, valueMin: await (0, utils_1.getClusterAttributeValue)(endpoint, "genAnalogOutput", "minPresentValue", undefined), valueMax: await (0, utils_1.getClusterAttributeValue)(endpoint, "genAnalogOutput", "maxPresentValue", undefined), valueStep: await (0, utils_1.getClusterAttributeValue)(endpoint, "genAnalogOutput", "resolution", undefined), cluster: "genAnalogOutput", attribute: "presentValue", reporting: { min: "MIN", max: "MAX", change: 1 }, description: description, access: "ALL", endpointNames, unit, }; generated.push(new ExtendGenerator({ extend: m.numeric, args, source: "numeric" })); } return generated; } //# sourceMappingURL=generateDefinition.js.map