UNPKG

zigbee-herdsman-converters

Version:

Collection of device converters to be used with zigbee-herdsman

1,126 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 () { 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.definitions = void 0; const zigbee_herdsman_1 = require("zigbee-herdsman"); const fz = __importStar(require("../converters/fromZigbee")); const tz = __importStar(require("../converters/toZigbee")); const constants = __importStar(require("../lib/constants")); const develco_1 = require("../lib/develco"); const exposes = __importStar(require("../lib/exposes")); const logger_1 = require("../lib/logger"); const m = __importStar(require("../lib/modernExtend")); const reporting = __importStar(require("../lib/reporting")); const utils = __importStar(require("../lib/utils")); 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 = { 0: "off", 1: "fault_only", 2: "motion_only", 255: "both", }; // develco specific converters const develco = { fz: { // Some Develco devices report strange values sometimes // https://github.com/Koenkk/zigbee2mqtt/issues/13329 electrical_measurement: { ...fz.electrical_measurement, convert: (model, msg, publish, options, meta) => { if (!Number.isNaN(msg.data.rmsVoltage) && !Number.isNaN(msg.data.rmsCurrent) && !Number.isNaN(msg.data.activePower)) { return fz.electrical_measurement.convert(model, msg, publish, options, meta); } }, }, metering: { ...fz.metering, convert: (model, msg, publish, options, meta) => { if (!Number.isNaN(msg.data.instantaneousDemand) && msg.data.currentSummDelivered !== 0) { return fz.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.develcoPulseConfiguration !== undefined) { 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.develcoInterfaceMode !== undefined) { result[utils.postfixWithEndpointName("interface_mode", msg, model, meta)] = constants.develcoInterfaceMode[msg.data.develcoInterfaceMode] !== undefined ? constants.develcoInterfaceMode[msg.data.develcoInterfaceMode] : msg.data.develcoInterfaceMode; } if (msg.data.status !== undefined) { 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.reliability !== undefined) { const lookup = { 0: "no_fault_detected", 7: "unreliable_other", 8: "process_error" }; result.reliability = utils.getFromLookup(msg.data.reliability, lookup); } if (msg.data.statusFlags !== undefined) { result.fault = msg.data.statusFlags === 1; } return result; }, }, led_control: { cluster: "genBasic", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { const state = {}; if (msg.data.develcoLedControl !== undefined) { 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.develcoAlarmOffDelay !== undefined) { state.occupancy_timeout = msg.data.develcoAlarmOffDelay; } return state; }, }, metering_emizb132: { cluster: "seMetering", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { if (utils.hasAlreadyProcessedMessage(msg, model)) return; const payload = {}; const multiplier = 1; // msg.endpoint.getClusterAttributeValue("seMetering", "multiplier") as number; const divisor = 1000; // msg.endpoint.getClusterAttributeValue("seMetering", "divisor") as number; const factor = multiplier && divisor ? multiplier / divisor : null; if (msg.data.currentSummDelivered !== undefined) { const value = msg.data.currentSummDelivered; if (value === 0 || value === 0xffffffffffff || Number.isNaN(value)) { return; } const property = utils.postfixWithEndpointName("energy", msg, model, meta); payload[property] = value * (factor ?? 1); } if (msg.data.currentSummReceived !== undefined) { const value = msg.data.currentSummReceived; const property = utils.postfixWithEndpointName("produced_energy", msg, model, meta); payload[property] = value * (factor ?? 1); } return payload; }, }, electrical_measurement_emizb132: { cluster: "haElectricalMeasurement", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { const interfaceModeLookup = { norwegian_han: { value: 0x0200, acCurrentDivisor: 10 }, norwegian_han_extra_load: { value: 0x0201, acCurrentDivisor: 10 }, aidon_meter: { value: 0x0202, acCurrentDivisor: 10 }, kaifa_and_kamstrup: { value: 0x0203, acCurrentDivisor: 1000 }, }; const result = fz.electrical_measurement.convert(model, msg, publish, options, meta); // Divisor for current depends on interface_mode, adjust converted values if (result && typeof result === "object") { const currentMode = meta.state?.interface_mode || "norwegian_han"; const divisor = interfaceModeLookup[currentMode]?.acCurrentDivisor || 10; const clusterDivisor = msg.endpoint.getClusterAttributeValue("haElectricalMeasurement", "acCurrentDivisor"); if (result.current !== undefined) { result.current = (result.current * clusterDivisor) / divisor; } if (result.current_phase_b !== undefined) { result.current_phase_b = (result.current_phase_b * clusterDivisor) / divisor; } if (result.current_phase_c !== undefined) { result.current_phase_c = (result.current_phase_c * clusterDivisor) / divisor; } } return result; }, }, ias_smoke_alarm_1_develco: { cluster: "ssIasZone", type: "commandStatusChangeNotification", convert: (model, msg, publish, options, meta) => { const zoneStatus = msg.data.zonestatus; return { smoke: (zoneStatus & 1) > 0, battery_low: (zoneStatus & (1 << 3)) > 0, supervision_reports: (zoneStatus & (1 << 4)) > 0, restore_reports: (zoneStatus & (1 << 5)) > 0, test: (zoneStatus & (1 << 8)) > 0, }; }, }, }, tz: { pulse_configuration: { key: ["pulse_configuration"], convertSet: async (entity, key, value, meta) => { await entity.write("seMetering", { develcoPulseConfiguration: value }, manufacturerOptions); return { 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 { 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); }, }, arm_mode: { key: ["arm_mode"], convertSet: async (entity, key, value, meta) => { utils.assertObject(value, key); await tz.arm_mode.convertSet?.(entity, key, { ...value, audiblenotif: value.audiblenotif ?? 1 }, meta); }, }, }, }; exports.definitions = [ { zigbeeModel: ["SPLZB-131"], model: "SPLZB-131", vendor: "Develco", description: "Power plug", toZigbee: [tz.on_off], ota: true, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.deviceTemperature(), m.electricityMeter({ acFrequency: true, fzMetering: develco.fz.metering, fzElectricalMeasurement: develco.fz.electrical_measurement }), m.onOff({ powerOnBehavior: false, configureReporting: false }), ], endpoint: (device) => { return { default: 2 }; }, configure: async (device, coordinatorEndpoint) => { // Device also has genOnOff on endpoint 1, but that fails to setup, disable configureReporting in m.onOff above // and configure it for endpoint 2 here instead. // https://github.com/Koenkk/zigbee2mqtt/issues/29548 await reporting.onOff(device.getEndpoint(2)); }, }, { zigbeeModel: ["SPLZB-132"], model: "SPLZB-132", vendor: "Develco", description: "Power plug", ota: true, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.deviceTemperature(), m.electricityMeter({ acFrequency: true, fzMetering: develco.fz.metering, fzElectricalMeasurement: develco.fz.electrical_measurement }), m.onOff(), ], endpoint: (device) => { return { default: 2 }; }, }, { zigbeeModel: ["SPLZB-134"], model: "SPLZB-134", vendor: "Develco", description: "Power plug (type G)", ota: true, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.deviceTemperature(), m.electricityMeter({ acFrequency: true, fzMetering: develco.fz.metering, fzElectricalMeasurement: develco.fz.electrical_measurement }), m.onOff(), ], endpoint: (device) => { return { default: 2 }; }, }, { zigbeeModel: ["SPLZB-137"], model: "SPLZB-137", vendor: "Develco", description: "Power plug", fromZigbee: [fz.on_off, develco.fz.electrical_measurement, develco.fz.metering], toZigbee: [tz.on_off], ota: true, exposes: [e.switch(), e.power(), e.current(), e.voltage(), e.energy(), e.ac_frequency()], extend: [develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions()], 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", extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.deviceTemperature(), m.electricityMeter({ acFrequency: true, fzMetering: develco.fz.metering, fzElectricalMeasurement: develco.fz.electrical_measurement }), m.onOff(), ], endpoint: (device) => { return { default: 2 }; }, }, { zigbeeModel: ["EMIZB-132"], model: "EMIZB-132", vendor: "Develco", description: "Wattle AMS HAN power-meter sensor", version: "0.0.1", ota: true, extend: [ develco_1.develcoModernExtend.addCustomDevelcoSeMeteringCluster(), develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), m.numeric({ name: "power", cluster: "haElectricalMeasurement", attribute: "totalActivePower", description: "Total active power.", unit: "W", access: "STATE_GET", reporting: { min: 5, max: "1_HOUR", change: 1 }, }), m.numeric({ name: "power_reactive", cluster: "haElectricalMeasurement", attribute: "totalReactivePower", description: "Total reactive power.", unit: "VAr", access: "STATE_GET", reporting: { min: 5, max: "1_HOUR", change: 1 }, }), m.enumLookup({ name: "interface_mode", cluster: "seMetering", attribute: "develcoInterfaceMode", description: "Specifies the configuration of the external HAN port interface.", entityCategory: "config", access: "ALL", lookup: { norwegian_han: 0x0200, norwegian_han_extra_load: 0x0201, aidon_meter: 0x0202, kaifa_and_kamstrup: 0x0203, }, zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DEVELCO }, }), m.electricityMeter({ power: false, voltage: { divisor: 10 }, current: { divisor: 10 }, threePhase: true, energy: { divisor: 1000, multiplier: 1 }, producedEnergy: { divisor: 1000, multiplier: 1 }, fzMetering: develco.fz.metering_emizb132, fzElectricalMeasurement: develco.fz.electrical_measurement_emizb132, }), ], }, { zigbeeModel: ["SMSZB-120", "GWA1512_SmokeSensor"], 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.ias_smoke_alarm_1_develco, fz.ias_enroll, fz.ias_wd, develco.fz.fault_status], toZigbee: [tz.warning, tz.ias_max_duration, tz.warning_simple], ota: true, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.temperature(), // TODO: ep 38 m.battery({ voltageToPercentage: { min: 2500, max: 3000 }, percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }), ], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(35); // Device supports only 4 binds (otherwise you get TABLE_FULL error) // https://github.com/Koenkk/zigbee2mqtt/issues/23684 if (endpoint.binds.some((b) => b.cluster.name === "genPollCtrl")) { await endpoint.unbind("genPollCtrl", coordinatorEndpoint); } await reporting.bind(endpoint, coordinatorEndpoint, ["ssIasZone", "ssIasWd", "genBinaryInput"]); await endpoint.read("ssIasZone", ["iasCieAddr", "zoneState", "zoneId"]); await endpoint.read("genBinaryInput", ["reliability", "statusFlags"]); await endpoint.read("ssIasWd", ["maxDuration"]); }, endpoint: (device) => { return { default: 35 }; }, exposes: [ 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: [fz.on_off, develco.fz.electrical_measurement, develco.fz.metering], toZigbee: [tz.on_off], ota: true, exposes: [e.switch(), e.power(), e.current(), e.voltage(), e.energy(), e.ac_frequency()], extend: [develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions()], 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.ias_smoke_alarm_1_develco, fz.ias_enroll, fz.ias_wd, develco.fz.fault_status], toZigbee: [tz.warning, tz.ias_max_duration, tz.warning_simple], ota: true, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.temperature(), // TODO: ep 38 m.battery({ voltageToPercentage: { min: 2500, max: 3000 }, percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }), ], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(35); // Device supports only 4 binds (otherwise you get TABLE_FULL error) // https://github.com/Koenkk/zigbee2mqtt/issues/23684 if (endpoint.binds.some((b) => b.cluster.name === "genPollCtrl")) { await endpoint.unbind("genPollCtrl", coordinatorEndpoint); } await reporting.bind(endpoint, coordinatorEndpoint, ["ssIasZone", "ssIasWd", "genBinaryInput"]); await endpoint.read("ssIasZone", ["iasCieAddr", "zoneState", "zoneId"]); await endpoint.read("genBinaryInput", ["reliability", "statusFlags"]); await endpoint.read("ssIasWd", ["maxDuration"]); }, endpoint: (device) => { return { default: 35 }; }, exposes: [ 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: [fz.ias_contact_alarm_1], toZigbee: [], exposes: [e.contact(), e.battery_low(), e.tamper()], ota: true, endpoint: (device) => { return { default: 35 }; }, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.temperature(), // TODO: ep 38 m.battery({ percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: true, }), ], }, { zigbeeModel: ["WISZB-121"], model: "WISZB-121", vendor: "Develco", description: "Window sensor", fromZigbee: [fz.ias_contact_alarm_1], toZigbee: [], exposes: [e.contact(), e.battery_low(), e.tamper()], ota: true, endpoint: (device) => { return { default: 35 }; }, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), m.battery({ voltageToPercentage: { min: 2500, max: 3000 }, percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }), ], }, { zigbeeModel: ["WISZB-134"], model: "WISZB-134", vendor: "Develco", description: "Window/door sensor", ota: true, endpoint: () => ({ default: 35 }), extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), m.iasZoneAlarm({ zoneType: "contact", zoneAttributes: ["alarm_1", "battery_low", "tamper"] }), m.battery({ voltageToPercentage: "3V_2100", percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }), ], }, { zigbeeModel: ["WISZB-137"], model: "WISZB-137", vendor: "Develco", description: "Vibration sensor", fromZigbee: [fz.ias_vibration_alarm_1], toZigbee: [], exposes: [e.battery_low(), e.vibration(), e.tamper()], endpoint: (device) => { return { default: 38 }; }, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.temperature(), m.battery({ voltageToPercentage: "3V_2100", percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }), ], }, { zigbeeModel: ["WISZB-138", "GWA1513_WindowSensor"], model: "WISZB-138", vendor: "Develco", description: "Window sensor", fromZigbee: [fz.ias_contact_alarm_1], toZigbee: [], exposes: [e.contact(), e.battery_low()], endpoint: (device) => { return { default: 35 }; }, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.temperature(), m.battery({ voltageToPercentage: { min: 2500, max: 3000 }, percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }), ], }, { zigbeeModel: ["MOSZB-130"], model: "MOSZB-130", vendor: "Develco", description: "Motion sensor", fromZigbee: [fz.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: [fz.ias_occupancy_alarm_1, 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 (utils.isDummyDevice(device) || Number(device.softwareBuildID?.split(".")[0]) >= 3) { dynExposes.push(e.numeric("occupancy_timeout", ea.ALL).withUnit("s").withValueMin(5).withValueMax(65535)); } dynExposes.push(e.tamper()); dynExposes.push(e.battery_low()); if (utils.isDummyDevice(device) || 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.")); } return dynExposes; }, ota: true, endpoint: (device) => { return { default: 35 }; }, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoIasZone(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), // Prevent excessive reports // https://github.com/Koenkk/zigbee-herdsman-converters/pull/10081 develco_1.develcoModernExtend.temperature({ reporting: { min: 60, max: 3600, change: 100 } }), m.illuminance({ reporting: { min: 300, max: 3600, change: 100 } }), m.battery({ voltageToPercentage: { min: 2500, max: 3000 }, percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }), ], configure: async (device, coordinatorEndpoint) => { // zigbee2mqtt#14277 some features are not available on older firmwares // modernExtend's readGenBasicPrimaryVersions is called before this one, should be fine const endpoint35 = device.getEndpoint(35); if (Number(device?.softwareBuildID?.split(".")[0]) >= 3) { await endpoint35.read("ssIasZone", ["develcoAlarmOffDelay"], manufacturerOptions); } if (Number(device?.softwareBuildID?.split(".")[0]) >= 4) { await endpoint35.read("genBasic", ["develcoLedControl"], manufacturerOptions); } }, }, { zigbeeModel: ["MOSZB-141"], model: "MOSZB-141", vendor: "Develco", description: "Motion sensor", extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), m.iasZoneAlarm({ zoneType: "occupancy", zoneAttributes: ["alarm_1", "battery_low"] }), ], }, { whiteLabel: [{ vendor: "Frient", model: "MOSZB-153", description: "Motion Sensor 2 Pet" }], zigbeeModel: ["MOSZB-153"], model: "MOSZB-153", vendor: "Develco", description: "Motion sensor 2 pet", fromZigbee: [develco.fz.led_control, develco.fz.ias_occupancy_timeout], toZigbee: [develco.tz.led_control, develco.tz.ias_occupancy_timeout], exposes: (device, options) => { const dynExposes = []; if (utils.isDummyDevice(device) || Number(device?.softwareBuildID?.split(".")[0]) >= 2) { dynExposes.push(e.numeric("occupancy_timeout", ea.ALL).withUnit("s").withValueMin(5).withValueMax(65535)); dynExposes.push(e.enum("led_control", ea.ALL, ["off", "fault_only", "motion_only", "both"]).withDescription("Control LED indicator usage.")); } return dynExposes; }, ota: true, endpoint: (device) => { return { default: 35 }; }, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoIasZone(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.temperature(), m.illuminance({ reporting: { min: 60, max: 3600, change: 500 } }), m.battery({ voltageToPercentage: { min: 2500, max: 3000 }, percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }), m.iasZoneAlarm({ zoneType: "occupancy", zoneAttributes: ["alarm_1"] }), ], configure: async (device, coordinatorEndpoint) => { if (device?.softwareBuildID && Number(device.softwareBuildID.split(".")[0]) >= 2) { const endpoint35 = device.getEndpoint(35); await endpoint35.read("ssIasZone", ["develcoAlarmOffDelay"], manufacturerOptions); await endpoint35.read("genBasic", ["develcoLedControl"], manufacturerOptions); } }, }, { 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", ota: true, endpoint: (device) => { return { default: 38 }; }, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.temperature(), m.humidity(), m.battery({ voltageToPercentage: { min: 2500, max: 3200 }, percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }), develco_1.develcoModernExtend.batteryLowAA(), ], }, { 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 }; }, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.addCustomDevelcoSeMeteringCluster(), ], 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: [fz.on_off, develco.fz.metering], toZigbee: [tz.on_off], exposes: [e.power(), e.energy(), e.switch()], endpoint: (device) => { return { default: 2 }; }, extend: [develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions()], 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: [fz.ias_water_leak_alarm_1], toZigbee: [], ota: true, exposes: [e.battery_low(), e.tamper(), e.water_leak()], endpoint: (device) => { return { default: 35 }; }, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.temperature(), // TODO: ep 38 m.battery({ voltageToPercentage: { min: 2800, max: 3000 }, percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }), ], }, { zigbeeModel: ["AQSZB-110"], model: "AQSZB-110", vendor: "Develco", description: "Air quality sensor", ota: true, endpoint: (device) => { return { default: 38 }; }, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoAirQuality(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.voc(), develco_1.develcoModernExtend.airQuality(), develco_1.develcoModernExtend.temperature(), m.humidity(), m.battery({ voltageToPercentage: { min: 2500, max: 3000 }, percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }), develco_1.develcoModernExtend.batteryLowAA(), ], }, { zigbeeModel: ["SIRZB-110"], model: "SIRZB-110", vendor: "Develco", description: "Customizable siren", fromZigbee: [fz.ias_enroll, fz.ias_wd, fz.ias_siren], toZigbee: [tz.warning, tz.warning_simple, tz.ias_max_duration, tz.squawk], extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), develco_1.develcoModernExtend.temperature(), m.battery({ voltageToPercentage: { min: 2500, max: 3000 }, percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }), ], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(43); await reporting.bind(endpoint, coordinatorEndpoint, ["ssIasZone", "ssIasWd", "genBasic"]); await endpoint.read("ssIasZone", ["iasCieAddr", "zoneState", "zoneId"]); await endpoint.read("ssIasWd", ["maxDuration"]); const endpoint2 = device.getEndpoint(1); await reporting.bind(endpoint2, coordinatorEndpoint, ["genOnOff"]); }, endpoint: (device) => { return { default: 43 }; }, exposes: [ 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: ["SIRZB-111"], model: "SIRZB-111", vendor: "Develco", description: "Customizable siren", fromZigbee: [fz.ias_enroll, fz.ias_wd, fz.ias_siren], toZigbee: [tz.warning, tz.warning_simple, tz.ias_max_duration, tz.squawk], extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), m.battery({ voltageToPercentage: { min: 2500, max: 3000 }, percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }), ], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(43); await reporting.bind(endpoint, coordinatorEndpoint, ["ssIasZone", "ssIasWd", "genBasic"]); await endpoint.read("ssIasZone", ["iasCieAddr", "zoneState", "zoneId"]); await endpoint.read("ssIasWd", ["maxDuration"]); const endpoint2 = device.getEndpoint(1); await reporting.bind(endpoint2, coordinatorEndpoint, ["genOnOff"]); }, endpoint: (device) => { return { default: 43 }; }, exposes: [ 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: [ fz.command_arm_with_transaction, fz.command_emergency, fz.ias_no_alarm, fz.ignore_iaszone_attreport, fz.ignore_iasace_commandgetpanelstatus, ], toZigbee: [develco.tz.arm_mode], exposes: [ e.battery_low(), 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: true, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), m.battery({ voltageToPercentage: { min: 3000, max: 4200 }, percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }), m.iasGetPanelStatusResponse({ audiblenotif: 1 }), ], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(44); const clusters = ["ssIasZone", "ssIasAce", "genIdentify"]; await reporting.bind(endpoint, coordinatorEndpoint, clusters); }, endpoint: (device) => { return { default: 44 }; }, }, { zigbeeModel: ["IOMZB-110"], model: "IOMZB-110", vendor: "Develco", description: "IO module", meta: { multiEndpoint: true }, extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), m.deviceEndpoints({ endpoints: { l1: 112, l2: 113, l3: 114, l4: 115, l11: 116, l12: 117 }, }), ...["l1", "l2", "l3", "l4"].map((ep, i) => m.binary({ name: "input", cluster: "genBinaryInput", attribute: "presentValue", description: `State of input ${i + 1}`, access: "STATE_GET", endpointName: ep, valueOn: ["ON", 1], valueOff: ["OFF", 0], reporting: { min: 0, max: "1_HOUR", change: null, }, })), m.onOff({ powerOnBehavior: false, endpointNames: ["l11", "l12"], }), develco_1.develcoModernExtend.customPulseTrigger({ endpointNames: ["l11", "l12"], }), ], }, { zigbeeModel: ["SBTZB-110"], model: "SBTZB-110", vendor: "Develco", description: "Smart button", fromZigbee: [fz.ewelink_action], toZigbee: [], ota: true, exposes: [e.action(["single"])], extend: [ develco_1.develcoModernExtend.addCustomClusterManuSpecificDevelcoGenBasic(), develco_1.develcoModernExtend.readGenBasicPrimaryVersions(), m.battery({ voltageToPercentage: { min: 2200, max: 3000 }, percentage: true, voltage: true, lowStatus: false, voltageReporting: true, percentageReporting: false, }