UNPKG

zigbee-herdsman-converters

Version:

Collection of device converters to be used with zigbee-herdsman

1,008 lines 72.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.definitions = void 0; const zigbee_herdsman_1 = require("zigbee-herdsman"); const fz = __importStar(require("../converters/fromZigbee")); const bosch_1 = require("../lib/bosch"); const constants_1 = require("../lib/constants"); 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 reporting_1 = require("../lib/reporting"); const globalStore = __importStar(require("../lib/store")); const utils = __importStar(require("../lib/utils")); const e = exposes.presets; const ea = exposes.access; const NS = "zhc:bosch"; // Universal Switch II const buttonMap = { config_led_top_left_press: 0x10, config_led_top_right_press: 0x11, config_led_bottom_left_press: 0x12, config_led_bottom_right_press: 0x13, config_led_top_left_longpress: 0x20, config_led_top_right_longpress: 0x21, config_led_bottom_left_longpress: 0x22, config_led_bottom_right_longpress: 0x23, }; // Universal Switch II const labelShortPress = `Specifies LED color (rgb) and pattern on short press as hex string. 0-2: RGB value (e.g. ffffff = white) 3: Light position (01=top, 02=bottom, 00=full) 4-7: Durations for sequence fade-in -> on -> fade-out -> off (e.g. 01020102) 8: Number of Repetitions (01=1 to ff=255) Example: ff1493000104010001`; // Universal Switch II const labelLongPress = `Specifies LED color (rgb) and pattern on long press as hex string. 0-2: RGB value (e.g. ffffff = white) 3: Light position (01=top, 02=bottom, 00=full) 4-7: Durations for sequence fade-in -> on -> fade-out -> off (e.g. 01020102) 8: Number of Repetitions (01=1 to ff=255) Example: ff4200000502050001`; // Universal Switch II const labelConfirmation = `Specifies LED color (rgb) and pattern of the confirmation response as hex string. 0-2: RGB value (e.g. ffffff = white) 3: Light position (01=top, 02=bottom, 00=full) 4-7: Durations for sequence fade-in -> on -> fade-out -> off (e.g. 01020102) 8: Number of Repetitions (01=1 to ff=255) Example: 30ff00000102010001`; const boschBmctRzSettings = { deviceModes: { switch: 0x00, pulsed: 0x01, }, switchTypes: { button: 0x05, rocker_switch: 0x07, none: 0x00, }, switchModes: { coupled: 0x00, decoupled: 0x01, }, hasDualSwitchInputs: false, }; const boschBmctDzSettings = { switchTypes: { button: 0x05, none: 0x00, }, switchModes: { coupled: 0x00, decoupled: 0x01, }, hasDualSwitchInputs: false, }; const boschExtend = { broadcastAlarm: () => { const sirenState = { smoke_off: 0x0000, smoke_on: 0x3c00, burglar_off: 0x0001, burglar_on: 0xb401, }; const exposes = [ e .enum("broadcast_alarm", ea.SET, Object.keys(sirenState)) .withDescription("Set siren state of all BSD-2 via broadcast") .withCategory("config"), ]; const toZigbee = [ { key: ["broadcast_alarm"], convertSet: async (entity, key, value, meta) => { if (key === "broadcast_alarm") { const index = utils.getFromLookup(value, sirenState); utils.assertEndpoint(entity); await entity.zclCommandBroadcast(255, zigbee_herdsman_1.ZSpec.BroadcastAddress.SLEEPY, "ssIasZone", "boschSmokeAlarmSiren", { data: index }, bosch_1.manufacturerOptions); return; } }, }, ]; return { exposes, toZigbee, isModernExtend: true, }; }, twinguard: () => { const smokeSensitivity = { low: 0x03, medium: 0x02, high: 0x01, }; const sirenState = { stop: 0x00, pre_alarm: 0x01, fire: 0x02, burglar: 0x03, }; const stateOffOn = { OFF: 0x00, ON: 0x01, }; const exposes = [ e.binary("smoke", ea.STATE, true, false).withDescription("Indicates whether the device detected smoke"), e.numeric("temperature", ea.STATE).withValueMin(0).withValueMax(65).withValueStep(0.1).withUnit("°C").withDescription("Temperature"), e.numeric("humidity", ea.STATE).withValueMin(0).withValueMax(100).withValueStep(0.1).withUnit("%").withDescription("Relative humidity"), e .numeric("eco2", ea.STATE) .withValueMin(500) .withValueMax(5500) .withValueStep(1) .withLabel("eCO₂") .withUnit("ppm") .withDescription("TVOC-derived CO₂-equivalent"), e.numeric("aqi", ea.STATE).withValueMin(0).withValueMax(500).withValueStep(1).withLabel("IAQ").withDescription("Index for Air Quality"), e.illuminance(), e .numeric("battery", ea.STATE) .withUnit("%") .withValueMin(0) .withValueMax(100) .withDescription("Remaining battery in %") .withCategory("diagnostic"), e.text("siren_state", ea.STATE).withDescription("Siren state").withCategory("diagnostic"), e.enum("alarm", ea.ALL, Object.keys(sirenState)).withDescription("Alarm mode for siren"), e.binary("self_test", ea.ALL, true, false).withDescription("Initiate self-test").withCategory("config"), e.enum("sensitivity", ea.ALL, Object.keys(smokeSensitivity)).withDescription("Sensitivity of the smoke detector").withCategory("config"), e.binary("pre_alarm", ea.ALL, "ON", "OFF").withDescription("Enable/disable pre-alarm").withCategory("config"), e.binary("heartbeat", ea.ALL, "ON", "OFF").withDescription("Enable/disable heartbeat (blue LED)").withCategory("config"), ]; const fromZigbee = [ { cluster: "twinguardSmokeDetector", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { const result = {}; if (msg.data.sensitivity !== undefined) { result.sensitivity = Object.keys(smokeSensitivity)[msg.data.sensitivity]; } return result; }, }, { cluster: "twinguardMeasurements", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { const result = {}; if (msg.data.humidity !== undefined) { const humidity = utils.toNumber(msg.data.humidity) / 100.0; if (utils.isInRange(0, 100, humidity)) { result.humidity = humidity; } } if (msg.data.airpurity !== undefined) { const iaq = utils.toNumber(msg.data.airpurity); result.aqi = iaq; const factorCo2 = 10; result.eco2 = iaq * factorCo2 + 500; } if (msg.data.temperature !== undefined) { result.temperature = utils.toNumber(msg.data.temperature) / 100.0; } if (msg.data.illuminance !== undefined) { result.illuminance = utils.precisionRound(msg.data.illuminance / 2, 2); } if (msg.data.battery !== undefined) { result.battery = utils.precisionRound(msg.data.battery / 2, 2); } return result; }, }, { cluster: "twinguardOptions", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { const result = {}; if (msg.data.pre_alarm !== undefined) { result.pre_alarm = Object.keys(stateOffOn)[msg.data.pre_alarm]; } return result; }, }, { cluster: "twinguardSetup", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { const result = {}; if (msg.data.heartbeat !== undefined) { result.heartbeat = Object.keys(stateOffOn)[msg.data.heartbeat]; } return result; }, }, { cluster: "twinguardAlarm", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { const result = {}; const lookup = { 2097184: "clear", 18874400: "self_test", 35651616: "burglar", 2097282: "pre_alarm", 2097281: "fire", 2097216: "silenced", }; if (msg.data.alarm_status !== undefined) { result.self_test = (msg.data.alarm_status & (1 << 24)) > 0; result.smoke = (msg.data.alarm_status & (1 << 7)) > 0; result.siren_state = lookup[msg.data.alarm_status]; } return result; }, }, { cluster: "genAlarms", type: ["commandAlarm", "readResponse"], convert: async (model, msg, publish, options, meta) => { const result = {}; const lookup = { 16: "fire", 17: "pre_alarm", 20: "clear", 22: "silenced", }; if ("alarmcode" in msg.data) { result.siren_state = lookup[msg.data.alarmcode]; if (msg.data.alarmcode === 0x10 || msg.data.alarmcode === 0x11) { await msg.endpoint.commandResponse("genAlarms", "alarm", { alarmcode: msg.data.alarmcode, clusterid: 0xe000 }, { direction: 1 }); } return result; } }, }, ]; const toZigbee = [ { key: ["sensitivity", "pre_alarm", "self_test", "alarm", "heartbeat"], convertSet: async (entity, key, value, meta) => { if (key === "sensitivity") { const index = utils.getFromLookup(value, smokeSensitivity); await entity.write("twinguardSmokeDetector", { sensitivity: index }, bosch_1.manufacturerOptions); return { state: { sensitivity: value } }; } if (key === "pre_alarm") { const index = utils.getFromLookup(value, stateOffOn); await entity.write("twinguardOptions", { pre_alarm: index }, bosch_1.manufacturerOptions); return { state: { pre_alarm: value } }; } if (key === "heartbeat") { const endpoint = meta.device.getEndpoint(12); const index = utils.getFromLookup(value, stateOffOn); await endpoint.write("twinguardSetup", { heartbeat: index }, bosch_1.manufacturerOptions); return { state: { heartbeat: value } }; } if (key === "self_test") { if (value) { await entity.command("twinguardSmokeDetector", "initiateTestMode", {}, bosch_1.manufacturerOptions); } } if (key === "alarm") { const endpoint = meta.device.getEndpoint(12); const index = utils.getFromLookup(value, sirenState); utils.assertEndpoint(entity); if (index === 0x00) { await entity.commandResponse("genAlarms", "alarm", { alarmcode: 0x16, clusterid: 0xe000 }, { direction: 1 }); await entity.commandResponse("genAlarms", "alarm", { alarmcode: 0x14, clusterid: 0xe000 }, { direction: 1 }); await endpoint.command("twinguardAlarm", "burglarAlarm", { data: 0x00 }, bosch_1.manufacturerOptions); } else if (index === 0x01) { await entity.commandResponse("genAlarms", "alarm", { alarmcode: 0x11, clusterid: 0xe000 }, { direction: 1 }); return { state: { siren_state: "pre_alarm" } }; } else if (index === 0x02) { await entity.commandResponse("genAlarms", "alarm", { alarmcode: 0x10, clusterid: 0xe000 }, { direction: 1 }); return { state: { siren_state: "fire" } }; } else if (index === 0x03) { await endpoint.command("twinguardAlarm", "burglarAlarm", { data: 0x01 }, bosch_1.manufacturerOptions); } } }, convertGet: async (entity, key, meta) => { switch (key) { case "sensitivity": await entity.read("twinguardSmokeDetector", ["sensitivity"], bosch_1.manufacturerOptions); break; case "pre_alarm": await entity.read("twinguardOptions", ["pre_alarm"], bosch_1.manufacturerOptions); break; case "heartbeat": await meta.device .getEndpoint(12) .read("twinguardSetup", ["heartbeat"], bosch_1.manufacturerOptions); break; case "alarm": case "self_test": await meta.device .getEndpoint(12) .read("twinguardAlarm", ["alarm_status"], bosch_1.manufacturerOptions); break; default: throw new Error(`Unhandled key boschExtend.twinguard.toZigbee.convertGet ${key}`); } }, }, ]; return { exposes, fromZigbee, toZigbee, isModernExtend: true, }; }, }; const tzLocal = { bhius_config: { key: Object.keys(buttonMap), convertGet: async (entity, key, meta) => { if (buttonMap[key] === undefined) { throw new Error(`Unknown key ${key}`); } await entity.read("boschSpecific", [buttonMap[key]], bosch_1.manufacturerOptions); }, convertSet: async (entity, key, value, meta) => { if (buttonMap[key] === undefined) { return; } const buffer = Buffer.from(value, "hex"); if (buffer.length !== 9) throw new Error(`Invalid configuration length: ${buffer.length} (should be 9)`); const payload = { [buttonMap[key]]: { value: buffer, type: 65 }, }; await entity.write("boschSpecific", payload, bosch_1.manufacturerOptions); const result = {}; result[key] = value; return { state: result }; }, }, }; const fzLocal = { bhius_button_press: { cluster: "boschSpecific", type: "raw", options: [e.text("led_response", ea.ALL).withLabel("LED config (confirmation response)").withDescription(labelConfirmation)], convert: (model, msg, publish, options, meta) => { const sequenceNumber = msg.data.readUInt8(3); const buttonId = msg.data.readUInt8(4); const longPress = msg.data.readUInt8(5); const duration = msg.data.readUInt16LE(6); // biome-ignore lint/suspicious/noImplicitAnyLet: ignored using `--suppress` let buffer; if (options.led_response != null) { buffer = Buffer.from(options.led_response, "hex"); if (buffer.length !== 9) { logger_1.logger.error(`Invalid length of led_response: ${buffer.length} (should be 9)`, NS); buffer = Buffer.from("30ff00000102010001", "hex"); } } else { buffer = Buffer.from("30ff00000102010001", "hex"); } if (utils.hasAlreadyProcessedMessage(msg, model, sequenceNumber)) return; const buttons = { 0: "top_left", 1: "top_right", 2: "bottom_left", 3: "bottom_right" }; let command = ""; if (buttonId in buttons) { if (longPress && duration > 0) { if (globalStore.hasValue(msg.endpoint, buttons[buttonId])) return; globalStore.putValue(msg.endpoint, buttons[buttonId], duration); command = "longpress"; } else { globalStore.clearValue(msg.endpoint, buttons[buttonId]); command = longPress ? "longpress_release" : "release"; msg.endpoint .command("boschSpecific", "confirmButtonPressed", { data: buffer }, { sendPolicy: "immediate" }) .catch((error) => { }); } return { action: `button_${buttons[buttonId]}_${command}` }; } logger_1.logger.error(`Received message with unknown command ID ${buttonId}. Data: 0x${msg.data.toString("hex")}`, NS); }, }, bhius_config: { cluster: "boschSpecific", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { const result = {}; for (const id of Object.values(buttonMap)) { if (msg.data[id] !== undefined) { // TODO: type is assumed "Buffer" since using `toString("hex")` result[Object.keys(buttonMap).find((key) => buttonMap[key] === id)] = msg.data[id].toString("hex"); } } return result; }, }, }; exports.definitions = [ { zigbeeModel: ["RBSH-OS-ZB-EU"], model: "BSIR-EZ", vendor: "Bosch", description: "Outdoor siren", extend: [ bosch_1.boschBsirExtend.customPowerCfgCluster(), bosch_1.boschBsirExtend.customIasZoneCluster(), bosch_1.boschBsirExtend.customIasWdCluster(), bosch_1.boschBsirExtend.deviceState(), bosch_1.boschBsirExtend.alarmControl(), bosch_1.boschBsirExtend.iasZoneStatus(), bosch_1.boschBsirExtend.alarmMode(), bosch_1.boschBsirExtend.sirenVolume(), bosch_1.boschBsirExtend.sirenDuration(), bosch_1.boschBsirExtend.lightDuration(), bosch_1.boschBsirExtend.sirenDelay(), bosch_1.boschBsirExtend.lightDelay(), bosch_1.boschBsirExtend.primaryPowerSource(), bosch_1.boschBsirExtend.currentPowerSource(), bosch_1.boschBsirExtend.solarPanelVoltage(), bosch_1.boschGeneralExtend.batteryWithPercentageAndLowStatus({ percentageReportingConfig: { min: "MIN", max: "MAX", change: 1 }, }), ], ota: true, }, { zigbeeModel: ["RBSH-WS-ZB-EU"], model: "BSEN-W", vendor: "Bosch", description: "Water alarm (formerly known as BWA-1)", extend: [ bosch_1.boschWaterAlarmExtend.changedSensitivityLevel(), bosch_1.boschWaterAlarmExtend.waterAlarmCluster(), bosch_1.boschGeneralExtend.handleRenamedCustomCluster("boschSpecific", "boschWaterAlarm"), bosch_1.boschWaterAlarmExtend.waterAndTamperAlarm(), bosch_1.boschWaterAlarmExtend.muteAlarmControl(), bosch_1.boschWaterAlarmExtend.alarmOnMotion(), bosch_1.boschWaterAlarmExtend.testMode(), bosch_1.boschGeneralExtend.batteryWithPercentageAndLowStatus(), ], ota: true, }, { zigbeeModel: ["RBSH-SD-ZB-EU"], model: "BSD-2", vendor: "Bosch", description: "Smoke alarm II", extend: [ bosch_1.boschSmokeAlarmExtend.enforceDefaultSensitivityLevel(), bosch_1.boschSmokeAlarmExtend.customIasZoneCluster(), bosch_1.boschSmokeAlarmExtend.smokeAlarmAndButtonPushes(), bosch_1.boschSmokeAlarmExtend.alarmControl(), bosch_1.boschSmokeAlarmExtend.testMode(), bosch_1.boschSmokeAlarmExtend.battery(), ], }, { zigbeeModel: [ "RFDL-ZB", "RFDL-ZB-EU", "RFDL-ZB-H", "RFDL-ZB-K", "RFDL-ZB-CHI", "RFDL-ZB-MS", "RFDL-ZB-ES", "RFPR-ZB", "RFPR-ZB-EU", "RFPR-ZB-CHI", "RFPR-ZB-ES", "RFPR-ZB-MS", ], model: "RADION TriTech ZB", vendor: "Bosch", description: "Wireless motion detector", fromZigbee: [fz.temperature, fz.battery, fz.ias_occupancy_alarm_1], toZigbee: [], meta: { battery: { voltageToPercentage: { min: 2500, max: 3000 } } }, configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(1); await reporting.bind(endpoint, coordinatorEndpoint, ["msTemperatureMeasurement", "genPowerCfg"]); await reporting.temperature(endpoint); await reporting.batteryVoltage(endpoint); }, exposes: [e.temperature(), e.battery(), e.occupancy(), e.battery_low(), e.tamper()], extend: [m.illuminance()], }, { zigbeeModel: ["ISW-ZPR1-WP13"], model: "ISW-ZPR1-WP13", vendor: "Bosch", description: "Motion sensor", fromZigbee: [fz.temperature, fz.battery, fz.ias_occupancy_alarm_1, fz.ignore_iaszone_report], toZigbee: [], meta: { battery: { voltageToPercentage: { min: 2500, max: 3000 } } }, configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(5); await reporting.bind(endpoint, coordinatorEndpoint, ["msTemperatureMeasurement", "genPowerCfg"]); await reporting.temperature(endpoint); await reporting.batteryVoltage(endpoint); }, exposes: [e.temperature(), e.battery(), e.occupancy(), e.battery_low(), e.tamper()], }, { zigbeeModel: ["RBSH-TRV0-ZB-EU", "RBSH-TRV1-ZB-EU"], model: "BTH-RA", vendor: "Bosch", description: "Radiator thermostat II", meta: { overrideHaDiscoveryPayload: (payload) => { // Override climate discovery // https://github.com/Koenkk/zigbee2mqtt/pull/23075#issue-2355829475 if (payload.mode_command_topic?.endsWith("/system_mode")) { payload.mode_command_topic = payload.mode_command_topic.substring(0, payload.mode_command_topic.lastIndexOf("/system_mode")); payload.mode_command_template = "{% set values = " + `{ 'auto':'schedule','heat':'manual','off':'pause'} %}` + `{"operating_mode": "{{ values[value] if value in values.keys() else 'pause' }}"}`; payload.mode_state_template = "{% set values = " + `{'schedule':'auto','manual':'heat','pause':'off'} %}` + `{% set value = value_json.operating_mode %}{{ values[value] if value in values.keys() else 'off' }}`; payload.modes = ["off", "heat", "auto"]; } }, }, extend: [ bosch_1.boschThermostatExtend.customThermostatCluster(), bosch_1.boschThermostatExtend.customUserInterfaceCfgCluster(), bosch_1.boschThermostatExtend.raThermostat(), bosch_1.boschThermostatExtend.setpointChangeSource({ enableReporting: true }), bosch_1.boschThermostatExtend.operatingMode({ enableReporting: true }), bosch_1.boschThermostatExtend.windowOpenMode({ enableReporting: true }), bosch_1.boschThermostatExtend.boostHeating({ enableReporting: true }), bosch_1.boschThermostatExtend.remoteTemperature(), bosch_1.boschThermostatExtend.childLock(), bosch_1.boschThermostatExtend.displayBrightness(), bosch_1.boschThermostatExtend.displaySwitchOnDuration(), bosch_1.boschThermostatExtend.displayOrientation(), bosch_1.boschThermostatExtend.displayedTemperature(), bosch_1.boschThermostatExtend.valveAdaptation(), bosch_1.boschThermostatExtend.errorState({ enableReporting: true }), bosch_1.boschGeneralExtend.batteryWithPercentageAndLowStatus(), ], ota: true, }, { zigbeeModel: ["RBSH-RTH0-BAT-ZB-EU"], model: "BTH-RM", vendor: "Bosch", description: "Room thermostat II", meta: { overrideHaDiscoveryPayload: (payload) => { if (payload.mode_command_topic?.endsWith("/system_mode")) { payload.mode_command_topic = payload.mode_command_topic.substring(0, payload.mode_command_topic.lastIndexOf("/system_mode")); payload.mode_command_template = "{% set values = " + `{ 'auto':'schedule','heat':'manual','cool':'manual','off':'pause'} %}` + `{% if value == "heat" or value == "cool" %}` + `{"operating_mode": "manual", "system_mode": "{{ value }}"}` + "{% else %}" + `{"operating_mode": "{{ values[value] if value in values.keys() else 'pause' }}"}` + "{% endif %}"; payload.mode_state_template = "{% set values = " + `{'schedule':'auto','manual':'heat','pause':'off'} %}` + "{% set value = value_json.operating_mode %}" + `{% if value == "manual" %}` + "{{ value_json.system_mode }}" + "{% else %}" + `{{ values[value] if value in values.keys() else 'off' }}` + "{% endif %}"; payload.modes = ["off", "heat", "cool", "auto"]; } }, }, extend: [ bosch_1.boschGeneralExtend.handleZclVersionReadRequest(), bosch_1.boschThermostatExtend.customThermostatCluster(), bosch_1.boschThermostatExtend.customUserInterfaceCfgCluster(), bosch_1.boschThermostatExtend.operatingMode({ enableReporting: true }), bosch_1.boschThermostatExtend.rmThermostat(), bosch_1.boschThermostatExtend.setpointChangeSource({ enableReporting: true }), bosch_1.boschThermostatExtend.humidity(), bosch_1.boschThermostatExtend.cableSensorMode(), bosch_1.boschThermostatExtend.cableSensorTemperature(), bosch_1.boschThermostatExtend.windowOpenMode(), bosch_1.boschThermostatExtend.boostHeating(), bosch_1.boschThermostatExtend.childLock(), bosch_1.boschThermostatExtend.displayBrightness(), bosch_1.boschThermostatExtend.displaySwitchOnDuration(), bosch_1.boschThermostatExtend.activityLedState(), bosch_1.boschThermostatExtend.errorState({ enableReporting: true }), bosch_1.boschThermostatExtend.rmBattery(), ], ota: true, }, { zigbeeModel: ["RBSH-RTH0-ZB-EU"], model: "BTH-RM230Z", vendor: "Bosch", description: "Room thermostat II 230V", meta: { overrideHaDiscoveryPayload: (payload) => { if (payload.mode_command_topic?.endsWith("/system_mode")) { payload.mode_command_topic = payload.mode_command_topic.substring(0, payload.mode_command_topic.lastIndexOf("/system_mode")); payload.mode_command_template = "{% set values = " + `{ 'auto':'schedule','heat':'manual','cool':'manual','off':'pause'} %}` + `{% if value == "heat" or value == "cool" %}` + `{"operating_mode": "manual", "system_mode": "{{ value }}"}` + "{% else %}" + `{"operating_mode": "{{ values[value] if value in values.keys() else 'pause' }}"}` + "{% endif %}"; payload.mode_state_template = "{% set values = " + `{'schedule':'auto','manual':'heat','pause':'off'} %}` + "{% set value = value_json.operating_mode %}" + `{% if value == "manual" %}` + "{{ value_json.system_mode }}" + "{% else %}" + `{{ values[value] if value in values.keys() else 'off' }}` + "{% endif %}"; payload.modes = ["off", "heat", "cool", "auto"]; } }, }, extend: [ bosch_1.boschGeneralExtend.handleZclVersionReadRequest(), bosch_1.boschThermostatExtend.customThermostatCluster(), bosch_1.boschThermostatExtend.customUserInterfaceCfgCluster(), bosch_1.boschThermostatExtend.relayState(), bosch_1.boschThermostatExtend.operatingMode({ enableReporting: true }), bosch_1.boschThermostatExtend.rmThermostat(), bosch_1.boschThermostatExtend.setpointChangeSource({ enableReporting: true }), bosch_1.boschThermostatExtend.humidity(), bosch_1.boschThermostatExtend.heaterType(), bosch_1.boschThermostatExtend.valveType(), bosch_1.boschThermostatExtend.cableSensorMode(), bosch_1.boschThermostatExtend.cableSensorTemperature(), bosch_1.boschThermostatExtend.windowOpenMode(), bosch_1.boschThermostatExtend.boostHeating(), bosch_1.boschThermostatExtend.childLock(), bosch_1.boschThermostatExtend.displayBrightness(), bosch_1.boschThermostatExtend.displaySwitchOnDuration(), bosch_1.boschThermostatExtend.activityLedState(), bosch_1.boschThermostatExtend.errorState({ enableReporting: true }), ], ota: true, }, { zigbeeModel: ["Champion"], model: "8750001213", vendor: "Bosch", description: "Twinguard", extend: [ m.deviceAddCustomCluster("twinguardSmokeDetector", { name: "twinguardSmokeDetector", ID: 0xe000, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.ROBERT_BOSCH_GMBH, attributes: { sensitivity: { name: "sensitivity", ID: 0x4003, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff }, }, commands: { initiateTestMode: { name: "initiateTestMode", ID: 0x00, parameters: [], }, }, commandsResponse: {}, }), m.deviceAddCustomCluster("twinguardMeasurements", { name: "twinguardMeasurements", ID: 0xe002, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.ROBERT_BOSCH_GMBH, attributes: { humidity: { name: "humidity", ID: 0x4000, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff }, unknown1: { name: "unknown1", ID: 0x4001, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff }, unknown2: { name: "unknown2", ID: 0x4002, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff }, airpurity: { name: "airpurity", ID: 0x4003, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff }, temperature: { name: "temperature", ID: 0x4004, type: zigbee_herdsman_1.Zcl.DataType.INT16, write: true, min: -32768 }, illuminance: { name: "illuminance", ID: 0x4005, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff }, battery: { name: "battery", ID: 0x4006, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff }, unknown3: { name: "unknown3", ID: 0x4007, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff }, unknown4: { name: "unknown4", ID: 0x4008, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff }, pressure: { name: "pressure", ID: 0x4009, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff }, // Not yet confirmed unknown6: { name: "unknown6", ID: 0x400a, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff }, unknown7: { name: "unknown7", ID: 0x400b, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff }, unknown8: { name: "unknown8", ID: 0x400c, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff }, }, commands: {}, commandsResponse: {}, }), m.deviceAddCustomCluster("twinguardOptions", { name: "twinguardOptions", ID: 0xe004, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.ROBERT_BOSCH_GMBH, attributes: { unknown1: { name: "unknown1", ID: 0x4000, type: zigbee_herdsman_1.Zcl.DataType.BITMAP8, write: true }, // 0,1 ??? read during pairing pre_alarm: { name: "pre_alarm", ID: 0x4001, type: zigbee_herdsman_1.Zcl.DataType.BITMAP8, write: true }, // 0,1 on/off }, commands: {}, commandsResponse: {}, }), m.deviceAddCustomCluster("twinguardSetup", { name: "twinguardSetup", ID: 0xe006, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.ROBERT_BOSCH_GMBH, attributes: { unknown1: { name: "unknown1", ID: 0x5003, type: zigbee_herdsman_1.Zcl.DataType.INT8, write: true, min: -128 }, // perhaps signal strength? -7? unknown2: { name: "unknown2", ID: 0x5004, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff }, // ???? heartbeat: { name: "heartbeat", ID: 0x5005, type: zigbee_herdsman_1.Zcl.DataType.BITMAP8, write: true }, // 0 }, commands: { pairingCompleted: { name: "pairingCompleted", ID: 0x01, parameters: [], }, }, commandsResponse: {}, }), m.deviceAddCustomCluster("twinguardAlarm", { name: "twinguardAlarm", ID: 0xe007, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.ROBERT_BOSCH_GMBH, attributes: { alarm_status: { name: "alarm_status", ID: 0x5000, type: zigbee_herdsman_1.Zcl.DataType.BITMAP32, write: true }, }, commands: { burglarAlarm: { name: "burglarAlarm", ID: 0x01, parameters: [ { name: "data", type: zigbee_herdsman_1.Zcl.DataType.UINT8, max: 0xff }, // data:1 trips the siren data:0 should stop the siren ], }, }, commandsResponse: {}, }), boschExtend.twinguard(), ], configure: async (device, coordinatorEndpoint) => { await reporting.bind(device.getEndpoint(7), coordinatorEndpoint, ["genPollCtrl"]); await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genAlarms", "twinguardSmokeDetector", "twinguardOptions"]); await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["twinguardMeasurements"]); await reporting.bind(device.getEndpoint(12), coordinatorEndpoint, ["twinguardSetup", "twinguardAlarm"]); await device.getEndpoint(1).read("twinguardOptions", ["unknown1"], bosch_1.manufacturerOptions); // Needed for pairing await device .getEndpoint(12) .command("twinguardSetup", "pairingCompleted", {}, bosch_1.manufacturerOptions); // Needed for pairing await device .getEndpoint(1) .write("twinguardSmokeDetector", { sensitivity: 0x0002 }, bosch_1.manufacturerOptions); // Setting defaults await device.getEndpoint(1).write("twinguardOptions", { pre_alarm: 0x01 }, bosch_1.manufacturerOptions); // Setting defaults await device.getEndpoint(12).write("twinguardSetup", { heartbeat: 0x01 }, bosch_1.manufacturerOptions); // Setting defaults await device .getEndpoint(1) .read("twinguardSmokeDetector", ["sensitivity"], bosch_1.manufacturerOptions); await device.getEndpoint(1).read("twinguardOptions", ["pre_alarm"], bosch_1.manufacturerOptions); await device.getEndpoint(12).read("twinguardSetup", ["heartbeat"], bosch_1.manufacturerOptions); }, }, { zigbeeModel: ["RFPR-ZB-SH-EU"], model: "BSEN-M", vendor: "Bosch", description: "Motion detector", extend: [ bosch_1.boschBsenExtend.changedCheckinInterval(), bosch_1.boschBsenExtend.tamperAndOccupancyAlarm(), bosch_1.boschBsenExtend.battery(), bosch_1.boschBsenExtend.sensitivityLevel(), bosch_1.boschBsenExtend.testMode(), bosch_1.boschBsenExtend.illuminance(), bosch_1.boschBsenExtend.temperature(), ], }, { zigbeeModel: ["RBSH-SP-ZB-EU", "RBSH-SP-ZB-FR", "RBSH-SP-ZB-GB"], model: "BSP-FZ2", vendor: "Bosch", description: "Smart plug compact (type F plug)", extend: [ bosch_1.boschGeneralEnergyDeviceExtend.customMeteringCluster(), bosch_1.boschSmartPlugExtend.smartPlugCluster(), bosch_1.boschGeneralExtend.handleRenamedCustomCluster("boschSpecific", "boschEnergyDevice"), bosch_1.boschSmartPlugExtend.onOff(), bosch_1.boschGeneralEnergyDeviceExtend.autoOff(), bosch_1.boschSmartPlugExtend.electricityMeter(), bosch_1.boschGeneralEnergyDeviceExtend.resetEnergyMeters(), ], version: "0.0.1", ota: true, whiteLabel: [ { vendor: "Bosch", model: "BSP-EZ2", description: "Smart plug compact (type E plug)", fingerprint: [{ modelID: "RBSH-SP-ZB-FR" }] }, { vendor: "Bosch", model: "BSP-GZ2", description: "Smart plug compact (type G plug)", fingerprint: [{ modelID: "RBSH-SP-ZB-GB" }] }, ], }, { zigbeeModel: ["RBSH-SP2-ZB-EU"], model: "BSP-FD", vendor: "Bosch", description: "Smart plug compact [+M]", extend: [ bosch_1.boschGeneralExtend.handleZclVersionReadRequest(), bosch_1.boschGeneralEnergyDeviceExtend.customMeteringCluster(), bosch_1.boschSmartPlugExtend.smartPlugCluster(), bosch_1.boschSmartPlugExtend.onOff(), bosch_1.boschGeneralEnergyDeviceExtend.autoOff(), bosch_1.boschSmartPlugExtend.ledBrightness(), bosch_1.boschSmartPlugExtend.energySavingMode(), bosch_1.boschSmartPlugExtend.electricityMeter({ producedEnergy: true }), bosch_1.boschGeneralEnergyDeviceExtend.resetEnergyMeters(), ], }, { zigbeeModel: ["RBSH-SWD-ZB"], model: "BSEN-C2", vendor: "Bosch", description: "Door/window contact II", extend: [ bosch_1.boschDoorWindowContactExtend.doorWindowContactCluster(), bosch_1.boschGeneralExtend.handleRenamedCustomCluster("boschSpecific", "boschDoorWindowContactCluster"), bosch_1.boschDoorWindowContactExtend.reportContactState(), bosch_1.boschDoorWindowContactExtend.reportButtonActions(), bosch_1.boschDoorWindowContactExtend.breakFunctionality(), bosch_1.boschGeneralExtend.batteryWithPercentageAndLowStatus(), ], ota: true, }, { zigbeeModel: ["RBSH-SWDV-ZB"], model: "BSEN-CV", vendor: "Bosch", description: "Door/window contact II plus", extend: [ bosch_1.boschDoorWindowContactExtend.doorWindowContactCluster(), bosch_1.boschGeneralExtend.handleRenamedCustomCluster("boschSpecific", "boschDoorWindowContactCluster"), bosch_1.boschDoorWindowContactExtend.reportContactState(), bosch_1.boschDoorWindowContactExtend.reportButtonActions(), bosch_1.boschDoorWindowContactExtend.vibrationDetection(), bosch_1.boschDoorWindowContactExtend.breakFunctionality(), bosch_1.boschGeneralExtend.batteryWithPercentageAndLowStatus(), ], }, { zigbeeModel: ["RBSH-SWD2-ZB"], model: "BSEN-C2D", vendor: "Bosch", description: "Door/window contact II [+M]", extend: [ bosch_1.boschDoorWindowContactExtend.doorWindowContactCluster(), bosch_1.boschGeneralExtend.handleRenamedCustomCluster("boschSpecific", "boschDoorWindowContactCluster"), bosch_1.boschDoorWindowContactExtend.reportContactState(), bosch_1.boschDoorWindowContactExtend.reportButtonActions({ doublePressSupported: true }), bosch_1.boschDoorWindowContactExtend.breakFunctionality(), bosch_1.boschGeneralExtend.batteryWithPercentageAndLowStatus(), ], }, { zigbeeModel: ["RBSH-MMD-ZB-EU"], model: "BMCT-DZ", vendor: "Bosch", description: "Phase-cut dimmer", extend: [ bosch_1.boschGeneralExtend.handleZclVersionReadRequest(), m.deviceAddCustomCluster("boschEnergyDevice", { name: "boschEnergyDevice", ID: 0xfca0, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.ROBERT_BOSCH_GMBH, attributes: { switchType: { name: "switchType", ID: 0x0001, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, write: true, max: 0xff }, childLock: { name: "childLock", ID: 0x0008, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN, write: true }, dimmerType: { name: "dimmerType", ID: 0x0022, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, write: true, max: 0xff }, minimumBrightness: { name: "minimumBrightness", ID: 0x0025, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff }, maximumBrightness: { name: "maximumBrightness", ID: 0x0026, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff }, switchMode: { name: "switchMode", ID: 0x0031, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN, write: true }, }, commands: {}, commandsResponse: {}, }), bosch_1.boschGeneralExtend.handleRenamedCustomCluster("boschSpecific", "boschEnergyDevice"), m.light({ configureReporting: true, levelConfig: { features: ["on_level", "current_level_startup"] }, powerOnBehavior: true, effect: false, }), bosch_1.boschBmctExtend.switchType({ switchTypeLookup: boschBmctDzSettings.switchTypes, }), bosch_1.boschBmctExtend.reportSwitchAction({ switchTypeLookup: boschBmctDzSettings.switchTypes, hasDualSwitchInputs: boschBmctDzSettings.hasDualSwitchInputs, }), bosch_1.boschBmctExtend.switchMode({ switchModeLookup: boschBmctDzSettings.switchModes, switchTypeLookup: boschBmctDzSettings.switchTypes, }), bosch_1.boschBmctExtend.childLock(), bosch_1.boschBmctExtend.brightnessRange(), bosch_1.boschBmctExtend.dimmerType(), ], ota: true, }, { zigbeeModel: ["RBSH-MMR-ZB-EU"], model: "BMCT-RZ", vendor: "Bosch", description: "Relay (potential free)", extend: [ bosch_1.boschGeneralExtend.handleZclVersionReadRequest(), m.deviceAddCustomCluster("boschEnergyDevice", { name: "boschEnergyDevice", ID: 0xfca0, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.ROBERT_BOSCH_GMBH, attributes: { switchType: { name: "switchType", ID: 0x0001, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, write: true, max: 0xff }, childLock: { name: "childLock", ID: 0x0008, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN, write: true }, pulseLength: { name: "pulseLength", ID: 0x0024, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff }, switchMode: { name: "switchMode", ID: 0x0031, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN, write: true }, actuatorType: { name: "actuatorType", ID: 0x0034, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, write: true, max: 0xff }, }, commands: {}, commandsResponse: {}, }), bosch_1.boschGeneralExtend.handleRenamedCustomCluster("boschSpecific", "boschEnergyDevice"), bosch_1.boschBmctExtend.rzDeviceModes({ deviceModesLookup: boschBmctRzSettings.deviceModes, }), m.onOff({ powerOnBehavior: false }), bosch_1.boschBmctExtend.switchType({ switchTypeLookup: boschBmctRzSettings.switchTypes, }), bosch_1.boschBmctExtend.reportSwitchAction({ switchTypeLookup: boschBmctRzSettings.switchTypes, hasDualSwitchInputs: boschBmctRzSettings.hasDualSwitchInputs, }), bosch_1.boschBmctExtend.switchMode({ switchModeLookup: boschBmctRzSettings.switchModes, switchTypeLookup: boschBmctRzSettings.switchTypes, }), bosch_1.boschBmctExtend.childLock(), bosch_1.boschGeneralEnergyDeviceExtend.autoOff(), bosch_1.boschBmctExtend.pulseLength({ updateDeviceMode: true, deviceModesLookup: boschBmctRzSettings.device