zigbee-herdsman-converters
Version:
Collection of device converters to be used with zigbee-herdsman
1,008 lines • 72.6 kB
JavaScript
"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