/* * * Bosch Twinguard Driver via Zigbee2MQTT * */ @Field String driverVersion = "v1.03 (13th December 2025)" @Field boolean debugMode = false #include BirdsLikeWires.library import groovy.transform.Field @Field int reportIntervalMinutes = 5 @Field String deviceName = "Bosch Twinguard" metadata { definition (name: "$deviceName", namespace: "BirdsLikeWires", author: "Andrew Davison", importUrl: "https://raw.githubusercontent.com/birdslikewires/hubitat/main/bosch/drivers/bosch_twinguard.groovy") { capability "AirQuality" capability "Alarm" capability "Battery" capability "CarbonDioxideMeasurement" capability "Configuration" capability "HealthCheck" capability "IlluminanceMeasurement" capability "PowerSource" capability "Refresh" capability "RelativeHumidityMeasurement" capability "Sensor" capability "SignalStrength" capability "SmokeDetector" capability "TemperatureMeasurement" attribute "healthStatus", "enum", ["offline", "online"] attribute "selfTest", "enum", ["true", "false"] attribute "siren", "string" attribute "voc", "number" command "both", [[name: "Triggers the pre-alarm chirp."]] command "off", [[name: "Stops any alarm."]] command "siren", [[name: "Triggers the fire alarm siren."]] command "strobe", [[name: "Triggers the burglar alarm siren."]] if (debugMode) { command "testCommand" } } } preferences { input name: "infoLogging", type: "bool", title: "Enable logging", defaultValue: true input name: "debugLogging", type: "bool", title: "Enable debug logging", defaultValue: false input name: "traceLogging", type: "bool", title: "Enable trace logging", defaultValue: false } void testCommand() { logging("${device} : Test Command", "info") } void configureSpecifics() { device.name = "$deviceName" updateDataValue("encoding", "MQTT") updateDataValue("isComponent", "false") sendEvent(name: "powerSource", value: "battery") sendEvent(name: "selfTest", value: "false") } void updateSpecifics() { configureSpecifics() } void refresh() { String ieee = getDataValue("ieee") parent.publishMQTT("$ieee", "get", "{\"alarm\": \"\"}") // Any get request seems to trigger a full report. } void ping() { refresh() } void both() { String ieee = getDataValue("ieee") parent.publishMQTT("$ieee", "set", "{\"alarm\": \"pre_alarm\"}") } void off() { String ieee = getDataValue("ieee") parent.publishMQTT("$ieee", "set", "{\"alarm\": \"stop\"}") parent.publishMQTT("$ieee", "get", "{\"alarm\": \"\"}") // Necessary otherwise it doesn't update until the next regular report. } void siren() { String ieee = getDataValue("ieee") parent.publishMQTT("$ieee", "set", "{\"alarm\": \"fire\"}") } void strobe() { String ieee = getDataValue("ieee") parent.publishMQTT("$ieee", "set", "{\"alarm\": \"burglar\"}") } void processMQTT(def json) { checkDriver() // Smoke if ("${json.smoke}" == "true") { sendEvent(name: "smoke", value: "detected") } else { String noSmoke = ("${json.self_test}" == "true") ? "tested" : "clear" sendEvent(name: "smoke", value: "$noSmoke") } // Sirens if (json.siren_state) { String alarmState switch("${json.siren_state}") { case "burglar": alarmState = "strobe" break case "fire": alarmState = "siren" break case "pre_alarm": alarmState = "both" break default: alarmState = "off" break } sendEvent(name: "alarm", value: "$alarmState") sendEvent(name: "siren", value: "${json.siren_state}") } // Environmental if (json.aqi) sendEvent(name: "airQualityIndex", value: "${json.aqi}") if (json.co2) sendEvent(name: "carbonDioxide", value: "${json.co2}", unit: "ppm") if (json.humidity) sendEvent(name: "humidity", value: "${json.humidity}", unit: "%rh") if (json.illuminance) sendEvent(name: "illuminance", value: "${json.illuminance}", unit: "lx") if (json.temperature) sendEvent(name: "temperature", value: "${json.temperature}", unit: "°C") if (json.voc) sendEvent(name: "voc", value: "${json.voc}", unit: "µg/m³") // Device if ("${json.self_test}" == "true") { runIn(10,refresh) // Needs a nudge to update when self-test is complete. sendEvent(name: "selfTest", value: "true") } else { sendEvent(name: "selfTest", value: "false") } // Admin mqttProcessBasics(json) updateHealthStatus() logging("${device} : processMQTT : ${json}", "debug") }