UNPKG

zigbee-herdsman-converters

Version:

Collection of device converters to be used with zigbee-herdsman

929 lines 52.7 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 (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 zigbee_herdsman_1 = require("zigbee-herdsman"); const exposes = __importStar(require("../lib/exposes")); const fromZigbee_1 = __importDefault(require("../converters/fromZigbee")); const toZigbee_1 = __importDefault(require("../converters/toZigbee")); const constants = __importStar(require("../lib/constants")); const reporting = __importStar(require("../lib/reporting")); const globalStore = __importStar(require("../lib/store")); const utils = __importStar(require("../lib/utils")); const ota = __importStar(require("../lib/ota")); const logger_1 = require("../lib/logger"); const e = exposes.presets; const ea = exposes.access; const NS = 'zhc:develco'; // develco specific cosntants const manufacturerOptions = { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DEVELCO }; /* MOSZB-1xx - ledControl - bitmap8 - r/w * 0x00 Disable LED when movement is detected. * 0x01 Enables periodic fault flashes. These flashes are used to indicate e.g. low battery level. * 0x02 Enables green application defined LED. This is e.g. used to indicate motion detection. * Default value 0xFF ( seems to be fault + motion) */ const develcoLedControlMap = { 0x00: 'off', 0x01: 'fault_only', 0x02: 'motion_only', 0xFF: 'both', }; // develco specific converters const develco = { configure: { read_sw_hw_version: async (device) => { for (const ep of device.endpoints) { if (ep.supportsInputCluster('genBasic')) { try { const data = await ep.read('genBasic', ['develcoPrimarySwVersion', 'develcoPrimaryHwVersion'], manufacturerOptions); if (data.hasOwnProperty('develcoPrimarySwVersion')) { device.softwareBuildID = data.develcoPrimarySwVersion.join('.'); } if (data.hasOwnProperty('develcoPrimaryHwVersion')) { device.hardwareVersion = data.develcoPrimaryHwVersion.join('.'); } } catch (error) { /* catch timeouts of sleeping devices */ } break; } } }, }, fz: { // Some Develco devices report strange values sometimes // https://github.com/Koenkk/zigbee2mqtt/issues/13329 electrical_measurement: { ...fromZigbee_1.default.electrical_measurement, convert: (model, msg, publish, options, meta) => { if (msg.data.rmsVoltage !== 0xFFFF && msg.data.rmsCurrent !== 0xFFFF && msg.data.activePower !== -0x8000) { return fromZigbee_1.default.electrical_measurement.convert(model, msg, publish, options, meta); } }, }, total_power: { cluster: 'haElectricalMeasurement', type: ['attributeReport', 'readResponse'], convert: (model, msg, publish, options, meta) => { const result = {}; if (msg.data.hasOwnProperty('totalActivePower') && msg.data['totalActivePower'] !== -0x80000000) { result[utils.postfixWithEndpointName('power', msg, model, meta)] = msg.data['totalActivePower']; } if (msg.data.hasOwnProperty('totalReactivePower') && msg.data['totalReactivePower'] !== -0x80000000) { result[utils.postfixWithEndpointName('power_reactive', msg, model, meta)] = msg.data['totalReactivePower']; } return result; }, }, device_temperature: { ...fromZigbee_1.default.device_temperature, convert: (model, msg, publish, options, meta) => { if (msg.data.currentTemperature !== -0x8000) { return fromZigbee_1.default.device_temperature.convert(model, msg, publish, options, meta); } }, }, temperature: { ...fromZigbee_1.default.temperature, convert: (model, msg, publish, options, meta) => { if (msg.data.measuredValue !== -0x8000 && msg.data.measuredValue !== 0xFFFF) { return fromZigbee_1.default.temperature.convert(model, msg, publish, options, meta); } }, }, metering: { ...fromZigbee_1.default.metering, convert: (model, msg, publish, options, meta) => { if (msg.data.instantaneousDemand !== -0x800000 && msg.data.currentSummDelivered?.[1] !== 0) { return fromZigbee_1.default.metering.convert(model, msg, publish, options, meta); } }, }, pulse_configuration: { cluster: 'seMetering', type: ['attributeReport', 'readResponse'], convert: (model, msg, publish, options, meta) => { const result = {}; if (msg.data.hasOwnProperty('develcoPulseConfiguration')) { result[utils.postfixWithEndpointName('pulse_configuration', msg, model, meta)] = msg.data['develcoPulseConfiguration']; } return result; }, }, interface_mode: { cluster: 'seMetering', type: ['attributeReport', 'readResponse'], convert: (model, msg, publish, options, meta) => { const result = {}; if (msg.data.hasOwnProperty('develcoInterfaceMode')) { result[utils.postfixWithEndpointName('interface_mode', msg, model, meta)] = constants.develcoInterfaceMode.hasOwnProperty(msg.data['develcoInterfaceMode']) ? constants.develcoInterfaceMode[msg.data['develcoInterfaceMode']] : msg.data['develcoInterfaceMode']; } if (msg.data.hasOwnProperty('status')) { result['battery_low'] = (msg.data.status & 2) > 0; result['check_meter'] = (msg.data.status & 1) > 0; } return result; }, }, fault_status: { cluster: 'genBinaryInput', type: ['attributeReport', 'readResponse'], convert: (model, msg, publish, options, meta) => { const result = {}; if (msg.data.hasOwnProperty('reliability')) { const lookup = { 0: 'no_fault_detected', 7: 'unreliable_other', 8: 'process_error' }; result.reliability = utils.getFromLookup(msg.data['reliability'], lookup); } if (msg.data.hasOwnProperty('statusFlags')) { result.fault = (msg.data['statusFlags'] === 1); } return result; }, }, voc: { cluster: 'develcoSpecificAirQuality', type: ['attributeReport', 'readResponse'], convert: (model, msg, publish, options, meta) => { // from Sensirion_Gas_Sensors_SGP3x_TVOC_Concept.pdf // "The mean molar mass of this mixture is 110 g/mol and hence, // 1 ppb TVOC corresponds to 4.5 μg/m3." const vocPpb = parseFloat(msg.data['measuredValue']); const voc = vocPpb * 4.5; const vocProperty = utils.postfixWithEndpointName('voc', msg, model, meta); // from aqszb-110-technical-manual-air-quality-sensor-04-08-20.pdf page 6, section 2.2 voc // this contains a ppb to level mapping table. let airQuality; const airQualityProperty = utils.postfixWithEndpointName('air_quality', msg, model, meta); if (vocPpb <= 65) { airQuality = 'excellent'; } else if (vocPpb <= 220) { airQuality = 'good'; } else if (vocPpb <= 660) { airQuality = 'moderate'; } else if (vocPpb <= 2200) { airQuality = 'poor'; } else if (vocPpb <= 5500) { airQuality = 'unhealthy'; } else if (vocPpb > 5500) { airQuality = 'out_of_range'; } else { airQuality = 'unknown'; } return { [vocProperty]: voc, [airQualityProperty]: airQuality }; }, }, voc_battery: { cluster: 'genPowerCfg', type: ['attributeReport', 'readResponse'], convert: async (model, msg, publish, options, meta) => { /* * Per the technical documentation for AQSZB-110: * To detect low battery the system can monitor the "BatteryVoltage" by setting up a reporting interval of every 12 hour. * When a voltage of 2.5V is measured the battery should be replaced. * Low batt LED indication–RED LED will blink twice every 60 second. */ const result = await fromZigbee_1.default.battery.convert(model, msg, publish, options, meta); if (result) result.battery_low = (result.voltage <= 2500); return result; }, }, led_control: { cluster: 'genBasic', type: ['attributeReport', 'readResponse'], convert: (model, msg, publish, options, meta) => { const state = {}; if (msg.data.hasOwnProperty('develcoLedControl')) { state['led_control'] = utils.getFromLookup(msg.data['develcoLedControl'], develcoLedControlMap); } return state; }, }, ias_occupancy_timeout: { cluster: 'ssIasZone', type: ['attributeReport', 'readResponse'], convert: (model, msg, publish, options, meta) => { const state = {}; if (msg.data.hasOwnProperty('develcoAlarmOffDelay')) { state['occupancy_timeout'] = msg.data['develcoAlarmOffDelay']; } return state; }, }, input: { cluster: 'genBinaryInput', type: ['attributeReport', 'readResponse'], convert: (model, msg, publish, options, meta) => { const result = {}; if (msg.data.hasOwnProperty('presentValue')) { const value = msg.data['presentValue']; result[utils.postfixWithEndpointName('input', msg, model, meta)] = value == 1; } return result; }, }, }, tz: { pulse_configuration: { key: ['pulse_configuration'], convertSet: async (entity, key, value, meta) => { await entity.write('seMetering', { 'develcoPulseConfiguration': value }, manufacturerOptions); return { readAfterWriteTime: 200, state: { 'pulse_configuration': value } }; }, convertGet: async (entity, key, meta) => { await entity.read('seMetering', ['develcoPulseConfiguration'], manufacturerOptions); }, }, interface_mode: { key: ['interface_mode'], convertSet: async (entity, key, value, meta) => { const payload = { 'develcoInterfaceMode': utils.getKey(constants.develcoInterfaceMode, value, undefined, Number) }; await entity.write('seMetering', payload, manufacturerOptions); return { readAfterWriteTime: 200, state: { 'interface_mode': value } }; }, convertGet: async (entity, key, meta) => { await entity.read('seMetering', ['develcoInterfaceMode'], manufacturerOptions); }, }, current_summation: { key: ['current_summation'], convertSet: async (entity, key, value, meta) => { await entity.write('seMetering', { 'develcoCurrentSummation': value }, manufacturerOptions); return { state: { 'current_summation': value } }; }, }, led_control: { key: ['led_control'], convertSet: async (entity, key, value, meta) => { const ledControl = utils.getKey(develcoLedControlMap, value, value, Number); await entity.write('genBasic', { 'develcoLedControl': ledControl }, manufacturerOptions); return { state: { led_control: value } }; }, convertGet: async (entity, key, meta) => { await entity.read('genBasic', ['develcoLedControl'], manufacturerOptions); }, }, ias_occupancy_timeout: { key: ['occupancy_timeout'], convertSet: async (entity, key, value, meta) => { let timeoutValue = utils.toNumber(value, 'occupancy_timeout'); if (timeoutValue < 5) { logger_1.logger.warning(`Minimum occupancy_timeout is 5, using 5 instead of ${timeoutValue}!`, NS); timeoutValue = 5; } await entity.write('ssIasZone', { 'develcoAlarmOffDelay': timeoutValue }, manufacturerOptions); return { state: { occupancy_timeout: timeoutValue } }; }, convertGet: async (entity, key, meta) => { await entity.read('ssIasZone', ['develcoAlarmOffDelay'], manufacturerOptions); }, }, input: { key: ['input'], convertGet: async (entity, key, meta) => { await entity.read('genBinaryInput', ['presentValue']); }, }, }, }; const definitions = [ { zigbeeModel: ['SPLZB-131'], model: 'SPLZB-131', vendor: 'Develco', description: 'Power plug', fromZigbee: [fromZigbee_1.default.on_off, develco.fz.electrical_measurement, develco.fz.metering, develco.fz.device_temperature], toZigbee: [toZigbee_1.default.on_off], ota: ota.zigbeeOTA, exposes: [e.switch(), e.power(), e.power_reactive(), e.current(), e.voltage(), e.energy(), e.device_temperature(), e.ac_frequency()], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(2); await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering', 'genDeviceTempCfg']); await reporting.onOff(endpoint); await reporting.deviceTemperature(endpoint); await reporting.readEletricalMeasurementMultiplierDivisors(endpoint, true); await reporting.activePower(endpoint, { change: 10 }); // Power reports with every 10W change await reporting.rmsCurrent(endpoint, { change: 20 }); // Current reports with every 20mA change await reporting.rmsVoltage(endpoint, { min: constants.repInterval.MINUTES_5, change: 400 }); // Limit reports to every 5m, or 4V await reporting.readMeteringMultiplierDivisor(endpoint); await reporting.currentSummDelivered(endpoint, { change: [0, 20] }); // Limit reports to once every 5m, or 0.02kWh await reporting.instantaneousDemand(endpoint, { min: constants.repInterval.MINUTES_5, change: 10 }); await reporting.acFrequency(endpoint, { change: 10 }); }, endpoint: (device) => { return { default: 2 }; }, }, { zigbeeModel: ['SPLZB-132'], model: 'SPLZB-132', vendor: 'Develco', description: 'Power plug', fromZigbee: [fromZigbee_1.default.on_off, develco.fz.electrical_measurement, develco.fz.metering, develco.fz.device_temperature], toZigbee: [toZigbee_1.default.on_off], ota: ota.zigbeeOTA, exposes: [e.switch(), e.power(), e.current(), e.voltage(), e.energy(), e.device_temperature(), e.ac_frequency()], options: [exposes.options.precision(`ac_frequency`)], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(2); await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering', 'genDeviceTempCfg']); await reporting.onOff(endpoint); await reporting.deviceTemperature(endpoint); // Set to true, to access the acFrequencyDivisor and acFrequencyMultiplier attribute. Not all devices support this. await reporting.readEletricalMeasurementMultiplierDivisors(endpoint, true); await reporting.activePower(endpoint, { change: 10 }); // Power reports with every 10W change await reporting.rmsCurrent(endpoint, { change: 20 }); // Current reports with every 20mA change await reporting.rmsVoltage(endpoint, { min: constants.repInterval.MINUTES_5, change: 400 }); // Limit reports to every 5m, or 4V await reporting.readMeteringMultiplierDivisor(endpoint); await reporting.currentSummDelivered(endpoint, { change: [0, 20] }); // Limit reports to once every 5m, or 0.02kWh await reporting.instantaneousDemand(endpoint, { min: constants.repInterval.MINUTES_5, change: 10 }); await reporting.acFrequency(endpoint); }, endpoint: (device) => { return { default: 2 }; }, }, { zigbeeModel: ['SPLZB-134'], model: 'SPLZB-134', vendor: 'Develco', description: 'Power plug (type G)', fromZigbee: [fromZigbee_1.default.on_off, develco.fz.electrical_measurement, develco.fz.metering, develco.fz.device_temperature], toZigbee: [toZigbee_1.default.on_off], ota: ota.zigbeeOTA, exposes: [e.switch(), e.power(), e.current(), e.voltage(), e.energy(), e.device_temperature()], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(2); await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering', 'genDeviceTempCfg']); await reporting.onOff(endpoint); await reporting.deviceTemperature(endpoint, { change: 2 }); // Device temperature reports with 2 degree change await reporting.readEletricalMeasurementMultiplierDivisors(endpoint); await reporting.activePower(endpoint, { change: 10 }); // Power reports with every 10W change await reporting.rmsCurrent(endpoint, { change: 20 }); // Current reports with every 20mA change await reporting.rmsVoltage(endpoint, { min: constants.repInterval.MINUTES_5, change: 400 }); // Limit reports to every 5m, or 4V await reporting.readMeteringMultiplierDivisor(endpoint); await reporting.currentSummDelivered(endpoint, { change: [0, 20] }); // Limit reports to once every 5m, or 0.02kWh await reporting.instantaneousDemand(endpoint, { min: constants.repInterval.MINUTES_5, change: 10 }); }, endpoint: (device) => { return { default: 2 }; }, }, { zigbeeModel: ['SPLZB-137'], model: 'SPLZB-137', vendor: 'Develco', description: 'Power plug', fromZigbee: [fromZigbee_1.default.on_off, develco.fz.electrical_measurement, develco.fz.metering], toZigbee: [toZigbee_1.default.on_off], ota: ota.zigbeeOTA, exposes: [e.switch(), e.power(), e.current(), e.voltage(), e.energy(), e.ac_frequency()], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(2); await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']); await reporting.onOff(endpoint); await reporting.readEletricalMeasurementMultiplierDivisors(endpoint, true); await reporting.activePower(endpoint); await reporting.rmsCurrent(endpoint); await reporting.rmsVoltage(endpoint); await reporting.readMeteringMultiplierDivisor(endpoint); await reporting.currentSummDelivered(endpoint); await reporting.acFrequency(endpoint); }, endpoint: (device) => { return { default: 2 }; }, }, { zigbeeModel: ['SMRZB-143'], model: 'SMRZB-143', vendor: 'Develco', description: 'Smart cable', fromZigbee: [fromZigbee_1.default.on_off, develco.fz.electrical_measurement, develco.fz.metering, develco.fz.device_temperature], toZigbee: [toZigbee_1.default.on_off], exposes: [e.switch(), e.power(), e.current(), e.voltage(), e.energy(), e.device_temperature()], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(2); await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering', 'genDeviceTempCfg']); await reporting.onOff(endpoint); await reporting.deviceTemperature(endpoint, { change: 2 }); // Device temperature reports with 2 degree change await reporting.readEletricalMeasurementMultiplierDivisors(endpoint); await reporting.activePower(endpoint, { change: 10 }); // Power reports with every 10W change await reporting.rmsCurrent(endpoint, { change: 20 }); // Current reports with every 20mA change await reporting.rmsVoltage(endpoint, { min: constants.repInterval.MINUTES_5, change: 400 }); // Limit reports to every 5m, or 4V await reporting.readMeteringMultiplierDivisor(endpoint); await reporting.currentSummDelivered(endpoint, { change: [0, 20] }); // Limit reports to once every 5m, or 0.02kWh await reporting.instantaneousDemand(endpoint, { min: constants.repInterval.MINUTES_5, change: 10 }); }, endpoint: (device) => { return { default: 2 }; }, }, { zigbeeModel: ['EMIZB-132'], model: 'EMIZB-132', vendor: 'Develco', description: 'Wattle AMS HAN power-meter sensor', fromZigbee: [develco.fz.metering, develco.fz.electrical_measurement, develco.fz.total_power], toZigbee: [toZigbee_1.default.EMIZB_132_mode], ota: ota.zigbeeOTA, configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(2); await reporting.bind(endpoint, coordinatorEndpoint, ['haElectricalMeasurement', 'seMetering']); try { // Some don't support these attributes // https://github.com/Koenkk/zigbee-herdsman-converters/issues/974#issuecomment-621465038 await reporting.readEletricalMeasurementMultiplierDivisors(endpoint); await reporting.rmsVoltage(endpoint); await reporting.rmsCurrent(endpoint); await endpoint.configureReporting('haElectricalMeasurement', [{ attribute: 'totalActivePower', minimumReportInterval: 5, maximumReportInterval: 3600, reportableChange: 1 }], manufacturerOptions); await endpoint.configureReporting('haElectricalMeasurement', [{ attribute: 'totalReactivePower', minimumReportInterval: 5, maximumReportInterval: 3600, reportableChange: 1 }], manufacturerOptions); } catch (e) { e; } await reporting.readMeteringMultiplierDivisor(endpoint); endpoint.saveClusterAttributeKeyValue('seMetering', { divisor: 1000, multiplier: 1 }); await reporting.currentSummDelivered(endpoint); await reporting.currentSummReceived(endpoint); await develco.configure.read_sw_hw_version(device); }, exposes: [e.numeric('power', ea.STATE).withUnit('W').withDescription('Total active power'), e.numeric('power_reactive', ea.STATE).withUnit('VAr').withDescription('Total reactive power'), e.energy(), e.current(), e.voltage(), e.current_phase_b(), e.voltage_phase_b(), e.current_phase_c(), e.voltage_phase_c()], onEvent: async (type, data, device) => { if (type === 'message' && data.type === 'attributeReport' && data.cluster === 'seMetering' && data.data['divisor']) { // Device sends wrong divisor (512) while it should be fixed to 1000 // https://github.com/Koenkk/zigbee-herdsman-converters/issues/3066 data.endpoint.saveClusterAttributeKeyValue('seMetering', { divisor: 1000, multiplier: 1 }); } }, }, { zigbeeModel: ['SMSZB-120'], model: 'SMSZB-120', vendor: 'Develco', description: 'Smoke detector with siren', whiteLabel: [ { vendor: 'Frient', model: '94430', description: 'Smart Intelligent Smoke Alarm' }, { vendor: 'Cavius', model: '2103', description: 'RF SMOKE ALARM, 5 YEAR 65MM' }, ], fromZigbee: [develco.fz.temperature, fromZigbee_1.default.battery, fromZigbee_1.default.ias_smoke_alarm_1_develco, fromZigbee_1.default.ignore_basic_report, fromZigbee_1.default.ias_enroll, fromZigbee_1.default.ias_wd, develco.fz.fault_status], toZigbee: [toZigbee_1.default.warning, toZigbee_1.default.ias_max_duration, toZigbee_1.default.warning_simple], ota: ota.zigbeeOTA, meta: { battery: { voltageToPercentage: '3V_2500' } }, configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(35); await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'ssIasZone', 'ssIasWd', 'genBasic', 'genBinaryInput']); await reporting.batteryVoltage(endpoint); await endpoint.read('ssIasZone', ['iasCieAddr', 'zoneState', 'zoneId']); await endpoint.read('genBinaryInput', ['reliability', 'statusFlags']); await endpoint.read('ssIasWd', ['maxDuration']); const endpoint2 = device.getEndpoint(38); await reporting.bind(endpoint2, coordinatorEndpoint, ['msTemperatureMeasurement']); await reporting.temperature(endpoint2, { min: constants.repInterval.MINUTE, max: constants.repInterval.MINUTES_10, change: 10 }); await develco.configure.read_sw_hw_version(device); }, endpoint: (device) => { return { default: 35 }; }, exposes: [e.temperature(), e.battery(), e.smoke(), e.battery_low(), e.test(), e.numeric('max_duration', ea.ALL).withUnit('s').withValueMin(0).withValueMax(600).withDescription('Duration of Siren'), e.binary('alarm', ea.SET, 'START', 'OFF').withDescription('Manual Start of Siren'), e.enum('reliability', ea.STATE, ['no_fault_detected', 'unreliable_other', 'process_error']) .withDescription('Indicates reason if any fault'), e.binary('fault', ea.STATE, true, false).withDescription('Indicates whether the device are in fault state')], }, { zigbeeModel: ['SPLZB-141'], model: 'SPLZB-141', vendor: 'Develco', description: 'Power plug', fromZigbee: [fromZigbee_1.default.on_off, develco.fz.electrical_measurement, develco.fz.metering], toZigbee: [toZigbee_1.default.on_off], exposes: [e.switch(), e.power(), e.current(), e.voltage(), e.energy(), e.ac_frequency()], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(2); await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']); await reporting.onOff(endpoint); await reporting.readEletricalMeasurementMultiplierDivisors(endpoint); await reporting.activePower(endpoint); await reporting.rmsCurrent(endpoint); await reporting.rmsVoltage(endpoint); await reporting.readMeteringMultiplierDivisor(endpoint); await reporting.currentSummDelivered(endpoint); await reporting.acFrequency(endpoint); }, endpoint: (device) => { return { default: 2 }; }, }, { zigbeeModel: ['HESZB-120'], model: 'HESZB-120', vendor: 'Develco', description: 'Fire detector with siren', whiteLabel: [ { vendor: 'Frient', model: '94431', description: 'Smart Intelligent Heat Alarm' }, ], fromZigbee: [develco.fz.temperature, fromZigbee_1.default.battery, fromZigbee_1.default.ias_smoke_alarm_1_develco, fromZigbee_1.default.ignore_basic_report, fromZigbee_1.default.ias_enroll, fromZigbee_1.default.ias_wd, develco.fz.fault_status], toZigbee: [toZigbee_1.default.warning, toZigbee_1.default.ias_max_duration, toZigbee_1.default.warning_simple], ota: ota.zigbeeOTA, meta: { battery: { voltageToPercentage: '3V_2500' } }, configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(35); await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'ssIasZone', 'ssIasWd', 'genBasic', 'genBinaryInput']); await reporting.batteryVoltage(endpoint); await endpoint.read('ssIasZone', ['iasCieAddr', 'zoneState', 'zoneId']); await endpoint.read('genBinaryInput', ['reliability', 'statusFlags']); await endpoint.read('ssIasWd', ['maxDuration']); const endpoint2 = device.getEndpoint(38); await reporting.bind(endpoint2, coordinatorEndpoint, ['msTemperatureMeasurement']); await reporting.temperature(endpoint2, { min: constants.repInterval.MINUTE, max: constants.repInterval.MINUTES_10, change: 10 }); await develco.configure.read_sw_hw_version(device); }, endpoint: (device) => { return { default: 35 }; }, exposes: [e.temperature(), e.battery(), e.smoke(), e.battery_low(), e.test(), e.numeric('max_duration', ea.ALL).withUnit('s').withValueMin(0).withValueMax(600).withDescription('Duration of Siren'), e.binary('alarm', ea.SET, 'START', 'OFF').withDescription('Manual Start of Siren'), e.enum('reliability', ea.STATE, ['no_fault_detected', 'unreliable_other', 'process_error']) .withDescription('Indicates reason if any fault'), e.binary('fault', ea.STATE, true, false).withDescription('Indicates whether the device are in fault state')], }, { zigbeeModel: ['WISZB-120'], model: 'WISZB-120', vendor: 'Develco', description: 'Window sensor', fromZigbee: [fromZigbee_1.default.ias_contact_alarm_1, fromZigbee_1.default.battery, develco.fz.temperature], toZigbee: [], exposes: [e.contact(), e.battery(), e.battery_low(), e.tamper(), e.temperature()], meta: { battery: { voltageToPercentage: '3V_2500' } }, ota: ota.zigbeeOTA, configure: async (device, coordinatorEndpoint) => { const endpoint35 = device.getEndpoint(35); const endpoint38 = device.getEndpoint(38); await reporting.bind(endpoint35, coordinatorEndpoint, ['genPowerCfg']); await reporting.bind(endpoint38, coordinatorEndpoint, ['msTemperatureMeasurement']); await reporting.batteryVoltage(endpoint35); await reporting.temperature(endpoint38); await develco.configure.read_sw_hw_version(device); }, }, { zigbeeModel: ['WISZB-121'], model: 'WISZB-121', vendor: 'Develco', description: 'Window sensor', fromZigbee: [fromZigbee_1.default.ias_contact_alarm_1, fromZigbee_1.default.battery], toZigbee: [], exposes: [e.contact(), e.battery(), e.battery_low(), e.tamper()], meta: { battery: { voltageToPercentage: '3V_2500' } }, ota: ota.zigbeeOTA, configure: async (device, coordinatorEndpoint) => { const endpoint35 = device.getEndpoint(35); await reporting.bind(endpoint35, coordinatorEndpoint, ['genPowerCfg']); await reporting.batteryVoltage(endpoint35); await develco.configure.read_sw_hw_version(device); }, }, { zigbeeModel: ['WISZB-137'], model: 'WISZB-137', vendor: 'Develco', description: 'Vibration sensor', fromZigbee: [fromZigbee_1.default.battery, fromZigbee_1.default.ias_vibration_alarm_1, fromZigbee_1.default.temperature], toZigbee: [], meta: { battery: { voltageToPercentage: '3V_2100' } }, exposes: [e.battery_low(), e.battery(), e.temperature(), e.vibration(), e.tamper()], configure: async (device, coordinatorEndpoint) => { const endpoint38 = device.getEndpoint(38); await reporting.bind(endpoint38, coordinatorEndpoint, ['msTemperatureMeasurement', 'genPowerCfg']); await reporting.temperature(endpoint38); await reporting.batteryVoltage(endpoint38); }, }, { zigbeeModel: ['WISZB-138', 'GWA1513_WindowSensor'], model: 'WISZB-138', vendor: 'Develco', description: 'Window sensor', fromZigbee: [fromZigbee_1.default.ias_contact_alarm_1, fromZigbee_1.default.battery, develco.fz.temperature], toZigbee: [], exposes: [e.contact(), e.battery(), e.battery_low(), e.temperature()], meta: { battery: { voltageToPercentage: '3V_2500' } }, configure: async (device, coordinatorEndpoint) => { const endpoint35 = device.getEndpoint(35); const endpoint38 = device.getEndpoint(38); await reporting.bind(endpoint35, coordinatorEndpoint, ['genPowerCfg']); await reporting.bind(endpoint38, coordinatorEndpoint, ['msTemperatureMeasurement']); await reporting.batteryVoltage(endpoint35); await reporting.temperature(endpoint38); await develco.configure.read_sw_hw_version(device); }, }, { zigbeeModel: ['MOSZB-130'], model: 'MOSZB-130', vendor: 'Develco', description: 'Motion sensor', fromZigbee: [fromZigbee_1.default.ias_occupancy_alarm_1], toZigbee: [], exposes: [e.occupancy(), e.battery_low(), e.tamper()], }, { zigbeeModel: ['MOSZB-140', 'GWA1511_MotionSensor'], model: 'MOSZB-140', vendor: 'Develco', description: 'Motion sensor', fromZigbee: [ develco.fz.temperature, fromZigbee_1.default.illuminance, fromZigbee_1.default.ias_occupancy_alarm_1, fromZigbee_1.default.battery, develco.fz.led_control, develco.fz.ias_occupancy_timeout, ], toZigbee: [develco.tz.led_control, develco.tz.ias_occupancy_timeout], exposes: (device, options) => { const dynExposes = []; dynExposes.push(e.occupancy()); if (device && device.softwareBuildID && Number(device.softwareBuildID.split('.')[0]) >= 3) { dynExposes.push(e.numeric('occupancy_timeout', ea.ALL).withUnit('s'). withValueMin(5).withValueMax(65535)); } dynExposes.push(e.temperature()); dynExposes.push(e.illuminance_lux()); dynExposes.push(e.tamper()); dynExposes.push(e.battery_low()); dynExposes.push(e.battery()); if (device && device.softwareBuildID && Number(device.softwareBuildID.split('.')[0]) >= 4) { dynExposes.push(e.enum('led_control', ea.ALL, ['off', 'fault_only', 'motion_only', 'both']). withDescription('Control LED indicator usage.')); } dynExposes.push(e.linkquality()); return dynExposes; }, ota: ota.zigbeeOTA, meta: { battery: { voltageToPercentage: '3V_2500' } }, endpoint: (device) => { return { default: 35 }; }, configure: async (device, coordinatorEndpoint) => { const endpoint39 = device.getEndpoint(39); await reporting.bind(endpoint39, coordinatorEndpoint, ['msIlluminanceMeasurement']); await reporting.illuminance(endpoint39, { min: constants.repInterval.MINUTE, max: constants.repInterval.MINUTES_10, change: 500 }); const endpoint38 = device.getEndpoint(38); await reporting.bind(endpoint38, coordinatorEndpoint, ['msTemperatureMeasurement']); await reporting.temperature(endpoint38, { min: constants.repInterval.MINUTE, max: constants.repInterval.MINUTES_10, change: 100 }); const endpoint35 = device.getEndpoint(35); await reporting.bind(endpoint35, coordinatorEndpoint, ['genPowerCfg']); await reporting.batteryVoltage(endpoint35, { min: constants.repInterval.HOUR, max: 43200, change: 100 }); // zigbee2mqtt#14277 some features are not available on older firmwares await develco.configure.read_sw_hw_version(device); if (device && device.softwareBuildID && Number(device.softwareBuildID.split('.')[0]) >= 3) { await endpoint35.read('ssIasZone', ['develcoAlarmOffDelay'], manufacturerOptions); } if (device && device.softwareBuildID && Number(device.softwareBuildID.split('.')[0]) >= 4) { await endpoint35.read('genBasic', ['develcoLedControl'], manufacturerOptions); } }, }, { zigbeeModel: ['MOSZB-141'], model: 'MOSZB-141', vendor: 'Develco', description: 'Motion sensor', fromZigbee: [fromZigbee_1.default.ias_occupancy_alarm_1], toZigbee: [], exposes: [e.occupancy(), e.battery_low()], }, { whiteLabel: [ { vendor: 'Frient', model: 'HMSZB-120', description: 'Temperature & humidity sensor', fingerprint: [{ modelID: 'HMSZB-120' }] }, ], zigbeeModel: ['HMSZB-110', 'HMSZB-120'], model: 'HMSZB-110', vendor: 'Develco', description: 'Temperature & humidity sensor', fromZigbee: [fromZigbee_1.default.battery, develco.fz.temperature, fromZigbee_1.default.humidity], toZigbee: [], exposes: [e.battery(), e.battery_low(), e.temperature(), e.humidity()], meta: { battery: { voltageToPercentage: '3V_2500_3200' } }, configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(38); await reporting.bind(endpoint, coordinatorEndpoint, ['msTemperatureMeasurement', 'msRelativeHumidity', 'genPowerCfg']); await reporting.temperature(endpoint, { min: constants.repInterval.MINUTE, max: constants.repInterval.MINUTES_10, change: 10 }); await reporting.humidity(endpoint, { min: constants.repInterval.MINUTE, max: constants.repInterval.MINUTES_10, change: 300 }); await reporting.batteryVoltage(endpoint, { min: constants.repInterval.HOUR, max: 43200, change: 100 }); await develco.configure.read_sw_hw_version(device); }, }, { zigbeeModel: ['ZHEMI101'], model: 'ZHEMI101', vendor: 'Develco', description: 'Energy meter', fromZigbee: [develco.fz.metering, develco.fz.pulse_configuration, develco.fz.interface_mode], toZigbee: [develco.tz.pulse_configuration, develco.tz.interface_mode, develco.tz.current_summation], endpoint: (device) => { return { 'default': 2 }; }, configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(2); await reporting.bind(endpoint, coordinatorEndpoint, ['seMetering']); await reporting.instantaneousDemand(endpoint); await reporting.readMeteringMultiplierDivisor(endpoint); }, exposes: [ e.power(), e.energy(), e.battery_low(), e.numeric('pulse_configuration', ea.ALL).withValueMin(0).withValueMax(65535) .withDescription('Pulses per kwh. Default 1000 imp/kWh. Range 0 to 65535'), e.enum('interface_mode', ea.ALL, ['electricity', 'gas', 'water', 'kamstrup-kmp', 'linky', 'IEC62056-21', 'DSMR-2.3', 'DSMR-4.0']) .withDescription('Operating mode/probe'), e.numeric('current_summation', ea.SET) .withDescription('Current summation value sent to the display. e.g. 570 = 0,570 kWh').withValueMin(0) .withValueMax(268435455), e.binary('check_meter', ea.STATE, true, false) .withDescription('Is true if communication problem with meter is experienced'), ], }, { zigbeeModel: ['SMRZB-332'], model: 'SMRZB-332', vendor: 'Develco', description: 'Smart relay DIN', fromZigbee: [fromZigbee_1.default.on_off, develco.fz.metering], toZigbee: [toZigbee_1.default.on_off], exposes: [e.power(), e.energy(), e.switch()], endpoint: (device) => { return { 'default': 2 }; }, configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(2); await reporting.bind(endpoint, coordinatorEndpoint, ['seMetering']); await reporting.instantaneousDemand(endpoint); await reporting.readMeteringMultiplierDivisor(endpoint); }, }, { zigbeeModel: ['FLSZB-110'], model: 'FLSZB-110', vendor: 'Develco', description: 'Flood alarm device ', fromZigbee: [fromZigbee_1.default.ias_water_leak_alarm_1, develco.fz.temperature, fromZigbee_1.default.battery], toZigbee: [], exposes: [e.battery_low(), e.tamper(), e.water_leak(), e.temperature(), e.battery_voltage()], configure: async (device, coordinatorEndpoint) => { const endpoint35 = device.getEndpoint(35); await reporting.bind(endpoint35, coordinatorEndpoint, ['genPowerCfg']); const endpoint38 = device.getEndpoint(38); await reporting.bind(endpoint38, coordinatorEndpoint, ['msTemperatureMeasurement']); await reporting.temperature(endpoint38, { min: constants.repInterval.MINUTE, max: constants.repInterval.MINUTES_10, change: 10 }); }, }, { zigbeeModel: ['AQSZB-110'], model: 'AQSZB-110', vendor: 'Develco', description: 'Air quality sensor', fromZigbee: [develco.fz.voc, develco.fz.voc_battery, develco.fz.temperature, fromZigbee_1.default.humidity], toZigbee: [], ota: ota.zigbeeOTA, exposes: [ e.voc(), e.temperature(), e.humidity(), e.battery(), e.battery_low(), e.enum('air_quality', ea.STATE, [ 'excellent', 'good', 'moderate', 'poor', 'unhealthy', 'out_of_range', 'unknown' ]).withDescription('Measured air quality'), ], meta: { battery: { voltageToPercentage: '3V_2500' } }, configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(38); await reporting.bind(endpoint, coordinatorEndpoint, ['develcoSpecificAirQuality', 'msTemperatureMeasurement', 'msRelativeHumidity', 'genPowerCfg']); await endpoint.configureReporting('develcoSpecificAirQuality', [{ attribute: 'measuredValue', minimumReportInterval: 60, maximumReportInterval: 3600, reportableChange: 10 }], manufacturerOptions); await reporting.temperature(endpoint, { min: constants.repInterval.MINUTE, max: constants.repInterval.MINUTES_10, change: 10 }); await reporting.humidity(endpoint, { min: constants.repInterval.MINUTE, max: constants.repInterval.MINUTES_10, change: 300 }); await reporting.batteryVoltage(endpoint, { min: constants.repInterval.HOUR, max: 43200, change: 100 }); await develco.configure.read_sw_hw_version(device); }, }, { zigbeeModel: ['SIRZB-110'], model: 'SIRZB-110', vendor: 'Develco', description: 'Customizable siren', fromZigbee: [develco.fz.temperature, fromZigbee_1.default.battery, fromZigbee_1.default.ias_enroll, fromZigbee_1.default.ias_wd, fromZigbee_1.default.ias_siren], toZigbee: [toZigbee_1.default.warning, toZigbee_1.default.warning_simple, toZigbee_1.default.ias_max_duration, toZigbee_1.default.squawk], meta: { battery: { voltageToPercentage: '3V_2500' } }, configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(43); await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'ssIasZone', 'ssIasWd', 'genBasic']); await reporting.batteryVoltage(endpoint); await endpoint.read('ssIasZone', ['iasCieAddr', 'zoneState', 'zoneId']); await endpoint.read('ssIasWd', ['maxDuration']); const endpoint2 = device.getEndpoint(1); await reporting.bind(endpoint2, coordinatorEndpoint, ['genOnOff']); await develco.configure.read_sw_hw_version(device); }, endpoint: (device) => { return { default: 43 }; }, exposes: [e.battery(), e.battery_low(), e.test(), e.warning(), e.squawk(), e.numeric('max_duration', ea.ALL).withUnit('s').withValueMin(0).withValueMax(900) .withDescription('Max duration of the siren'), e.binary('alarm', ea.SET, 'START', 'OFF').withDescription('Manual start of the siren')], }, { zigbeeModel: ['KEPZB-110'], model: 'KEYZB-110', vendor: 'Develco', description: 'Keypad', whiteLabel: [{ vendor: 'Frient', model: 'KEPZB-110' }], fromZigbee: [fromZigbee_1.default.command_arm_with_transaction, fromZigbee_1.default.battery, fromZigbee_1.default.command_emergency, fromZigbee_1.default.ias_no_alarm, fromZigbee_1.default.ignore_iaszone_attreport, fromZigbee_1.default.ignore_iasace_commandgetpanelstatus], toZigbee: [toZigbee_1.default.arm_mode], exposes: [e.battery(), e.battery_low(), e.battery_voltage(), e.tamper(), e.text('action_code', ea.STATE).withDescription('Pin code introduced.'), e.numeric('action_transaction', ea.STATE).withDescription('Last action transaction number.'), e.text('action_zone', ea.STATE).withDescription('Alarm zone. Default value 23'), e.action([ 'disarm', 'arm_day_zones', 'arm_night_zones', 'arm_all_zones', 'exit_delay', 'emergency' ])], ota: ota.zigbeeOTA, meta: { battery: { voltageToPercentage: '4LR6AA1_5v' } }, configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(44); const clusters = ['genPowerCfg', 'ssIasZone', 'ssIasAce', 'genIdentify']; await reporting.bind(endpoint, coordinatorEndpoint, clusters); await reporting.batteryVoltage(endpoint); }, endpoint: (device) => { return { default: 44 }; }, onEvent: async (type, data, device) => { if (type === 'message' && data.type === 'commandGetPanelStatus' && data.cluster === 'ssIasAce' && globalStore.hasValue(device.getEndpoint(44), 'panelStatus')) { const payload = { panelstatus: globalStore.getValue(device.getEndpoint(44), 'panelStatus'), secondsremain: 0x00, audiblenotif: 0x00, alarmstatus: 0x00, }; await data.endpoint.commandResponse('ssIasAce', 'getPanelStatusRsp', payload, {}, data.meta.zclTransactionSequenceNumber); } }, }, { zigbeeModel: ['IOMZB-110'], model: 'IOMZB-110', vendor: 'Develco', description: 'IO module', fromZigbee: [fromZigbee_1.default.on_off, develco.fz.input], toZigbee: [toZigbee_1.default.on_off, develco.tz.input], meta: { multiEndpoint: true }, exposes: [ e.binary('input', ea.STATE_GET, true, false).withEndpoint('l1').withDescription('State of input 1'), e.binary('input', ea.STATE_GET, true, false).w