SmartThings Community

Device Handler for Aqara Wired Wall Switch

dth_lighting
(Daniel S) #123

I have exactly the same issue. I think I still need to create a virtual switch. But it doesn’t find an endpoint. See screenshot. Any idea?

#124

didn’t know where to post this, but great news! The @simic DH works for the Aqara SINGLE button (non neutral) too! I was unable to use it before but now I can , thank you @simic !!!:partying_face:

#125

@simic can you make wireless button working? ( 2 buttons ) Most DH not working 2 buttons

(Antony Pugh) #126

No. due to an ST limitation. I am hoping it might change with all the coding upgrades they are doing to the underlying framework. but I have yet to see any detailed info on this.

#127

Hi @simic, I think I need some clarification regarding Step 3:

I’ve paired my 2 gang no neutral switches, they show up as one device that can only toggle the left paddle after I assign your DTH to it.

I tried using your kudled smartapp after this step, but it seems to be asking me to pick the virtual switches to bind, instead of creating a virtual switch for the right paddle. Am I supposed to find some other way of creating a virtual switch for the right paddle, then use your kudled smartapp to bind it?

(Gareth Davies) #128

Thanks, @simic I’ve downloaded your handler, it appears to work (mostly), but I have some questions…

1 - I couldn’t ever get a ‘catchall’ to appear while searching for new devices. I did however, manage to get ST to detect it as a ‘Thing’ so have since changed its details, using your device handler. Any reason you can think of for never receiving a catchall? (I must have tried a couple dozen times)

2 - how do I create a virtual switch that is linked to this? I can create virtual switches, but can’t figure out how to link…

Sorry for the noob questions here, but that’s exactly what I am, lol!

(Andy Chan) #129

you have to create the virtual switch, before using the kudled smartapp to bind.

(Andy Chan) #130

install the kudled smartapp linked.

(Gareth Davies) #131

I have created the virtual switch (2 actually, one for each button on there) and binded with the kudled smart app… no joy at all! I tried using this with 1 virtual switch, and 2, but to no avail. I just can’t get the thing to work properly with that second button for some reason!

I’ve all but given up and am using it as a dumb switch in my kitchen now…

Thanks though!

(Mike) #132

I’ve been happily using the DH created by @johndoyle for my no neutral single switch (lumi.ctrl_neutral1). Recently noticed that I can no longer control the switches from the app, and they don’t change state in the app when pressing the wall switch. I think this might coincide with the latest hub update (000.025.00026).
Anyone else having the same problem?

#133

I was using this DH by @Dschich happily and is now no longer working after the firmware upgrade. SmartThings has just crushed a Zigbee bug that rendered my SmartThings unusable. Damn

(Pardal) #134

Hey @Dschich. Nice work!
Do you have solution for changing the name of the devices?
Because when i rename both buttons, ST creates automatically another device (button) and even if i delete this new device, the main button works well but the second one doesn’t give me the status state.
Do you have solution?

Thanks

#135

The device handler used to work fine, but has recently started to cause some issues after an upgrade (the status of the switches wouldn’t get updated, which would also cause SmartApps to stop working as well).

I have therefore made some changes to the DTH to get it to work again.
I have the single gang wired switch, no neutral (QBKG04LM), so that’s what I have tested it on.

Below is the DTH that now works for me

/**
 *  Copyright 2017 johndoyle
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 */

metadata {
	definition (name: "Xiaomi Zigbee Mains Toggle Switch", namespace: "johndoyle", author: "John Doyle") {
        capability "Actuator"
        capability "Configuration"
        capability "Refresh"
        capability "Momentary"
        capability "Switch"
        capability "Temperature Measurement"

		fingerprint profileId:"0104", deviceId:"5C23", manufacturer:"LUMI", model:"lumi.ctrl_neutral1"
	}

    // simulator metadata
    simulator {
        // status messages
        status "on": "on/off: 1"
        status "off": "on/off: 0"

        // reply messages
        reply "zcl on-off on": "on/off: 1"
        reply "zcl on-off off": "on/off: 0"
    }
	
    preferences {
        input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature in degrees",
              range: "*..*", displayDuringSetup: false
		input title: "", description: "Use to correct any temperature variations by selecting an offset.", displayDuringSetup: false, type: "paragraph", element: "paragraph"
		input "debugOutput", "boolean", 
			title: "Enable debug logging?",
            description: "Use to display messages in Live Logging.",
			defaultValue: false,
			displayDuringSetup: true
	}

 // UI tile definitions
    tiles(scale: 2) {
        multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: false){
            tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
                 attributeState "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOff"
                 attributeState "off", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
                 attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOff"
                 attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
                 attributeState "offline", label:'${name}', icon:"st.Home.home30", backgroundColor:"#cccccc"
 			}
        }

        standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: false) {
            state "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOff"
            state "off", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
            state "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOff"
            state "turningOff", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
            state "offline", label:'${name}', icon:"st.Home.home30", backgroundColor:"#cccccc"
        }

        standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") {
            state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
        }

        valueTile("temperature", "device.temperature", width: 2, height: 2) {
			state("temperature", label:'${currentValue}°', unit:"C",
				backgroundColors:[
					[value: 0, color: "#153591"],
					[value: 5, color: "#1e9cbb"],
					[value: 10, color: "#90d2a7"],
					[value: 15, color: "#44b621"],
					[value: 20, color: "#f1d801"],
					[value: 25, color: "#d04e00"],
					[value: 30, color: "#bc2323"],
					[value: 44, color: "#1e9cbb"],
					[value: 59, color: "#90d2a7"],
					[value: 74, color: "#44b621"],
					[value: 84, color: "#f1d801"],
					[value: 95, color: "#d04e00"],
					[value: 96, color: "#bc2323"]  
				]
			)
		}
        standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
            state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
        }
        main(["switch"])
        details(["rich-control", "temperature", "refresh"])
    }
}


// Parse incoming device messages to generate events
def parse(String description) {
	def value = zigbee.parse(description)?.text
	Map map = [:]
        
    if (description?.startsWith('catchall:')) {
		map = parseCatchAllMessage(description)
	}
	else if (description?.startsWith('read attr -')) {
		map = parseReportAttributeMessage(description)
	}
    else if (description?.startsWith('on/off: ')){
    	def resultMap = zigbee.getKnownDescription(description)
        map = parseCustomMessage(description) 
	}

	def results = map ? createEvent(map) : null
	return results;
}

private Map parseCatchAllMessage(String description) {
	Map resultMap = [:]
	def cluster = zigbee.parse(description)    
    
    if (cluster.clusterId == 0x0006 && cluster.command == 0x0B){

    	def onoff = cluster.data[0]
        if (onoff == 1)
        	resultMap = createEvent(name: "switch", value: "on")
        else if (onoff == 0)
            resultMap = createEvent(name: "switch", value: "off")
    }
    else if (cluster.clusterId == 0x0000 && cluster.command == 0x0a){
    	if (state.debug) log.info "Periodic Update"
    }
	return resultMap
}

private Map parseReportAttributeMessage(String description) {

	Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
		def nameAndValue = param.split(":")
		map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
	}

	Map resultMap = [:]

    if (descMap.cluster == "0002" && descMap.attrId == "0000") {
    	def temp = convertHexToInt(descMap.value)
        if (tempOffset) {
			temp = (int) temp + (int) tempOffset
		}
    	if (state.debug) log.info "Reported Temp of " + temp + "°" + getTemperatureScale()
		resultMap = createEvent(name: "temperature", value: zigbee.parseHATemperatureValue("temperature: " + temp, "temperature: ", getTemperatureScale()), unit: getTemperatureScale())
	}
    else if (descMap.cluster == "0006" && descMap.endpoint == "02" && descMap.value[15] == "0") {
    	if (state.debug) log.info "Reported Switch Off"
    	resultMap = createEvent(name: "switch", value: "off")
    } 
    else if (descMap.cluster == "0006" && descMap.endpoint == "02" &&  descMap.value[15] == "1") {
    	if (state.debug) log.info "Reported Switch On"
    	resultMap = createEvent(name: "switch", value: "on")
    } 
	return resultMap
}

private Map parseCustomMessage(String description) {
	def result
	if (!isDuplicateCommand(state.lastUpdated, 2000)) {
        state.lastUpdated = new Date().time
        if (description?.startsWith('on/off: ')) {
            if (description == 'on/off: 0')
                result = createEvent(name: "switch", value: "off")
            else if (description == 'on/off: 1')
                result = createEvent(name: "switch", value: "on")
        }
	}
    return result
}

private isDuplicateCommand(lastExecuted, allowedMil) {
	!lastExecuted ? false : (lastExecuted + allowedMil > new Date().time)
}

def off() {
	if (device.endpointId == null) device.endpointId = 2
   	if (state.debug) log.info "Off()"
    "st cmd 0x${device.deviceNetworkId} 2 6 0 {}"
}

def on() {
	if (device.endpointId == null) device.endpointId = 2
   	if (state.debug) log.info "On()"
    "st cmd 0x${device.deviceNetworkId} 2 6 1 {}"
}

/**
 * PING is used by Device-Watch in attempt to reach the Device
 * */
def ping() {
   	if (state.debug) log.info "ping()"
	if (device.endpointId == null) device.endpointId = 2
    return zigbee.readAttribute(0x0006, 0x0000) +
        zigbee.readAttribute(0x0008, 0x0000) +
        zigbee.configureReporting(0x0006, 0x0000, 0x10, 0, 600, null) +
        zigbee.configureReporting(0x0008, 0x0000, 0x20, 1, 3600, 0x01)
}

def push() {
   	if (state.debug) log.info "push()"
	if (device.endpointId == null) device.endpointId = 2
	sendEvent(name: "switch", value: "on", isStateChange: true, displayed: false)
	sendEvent(name: "switch", value: "off", isStateChange: true, displayed: false)
	sendEvent(name: "momentary", value: "pushed", isStateChange: true)
}

def refresh() {
	state.debug = ("true" == debugOutput)
	if (state.debug) log.info "Refresh..."
    [
        "st rattr 0x${device.deviceNetworkId} 0x01 0x0002 0x0000", "delay 250", // CurrentTemperature
		"st rattr 0x${device.deviceNetworkId} 0x02 0x0006 0x0000", "delay 500", // On/Off
		"st rattr 0x${device.deviceNetworkId} 0x02 0x0008 0x0000", "delay 250",  // On/Off
		"st rattr 0x${device.deviceNetworkId} 0x02 0x0006 0x0000 0x10 0 600 null", "delay 500",
		"st rattr 0x${device.deviceNetworkId} 0x02 0x0008 0x0000 0x20 1 3600 0x01"
    ]
/**
 * 	Capability Returns
 *	 if (device.endpointId == null) device.endpointId = 2
 *   [
 *     	"st rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0000 0x0000", "delay 250", // ZCLVersion
 *		"st rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0000 0x0001", "delay 250", // ApplicationVersion
 *   	"st rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0000 0x0002", "delay 250", // StackVersion
 *    	"st rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0000 0x0003", "delay 250", // HWVersion
 *    	"st rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0000 0x0004", "delay 250", // ManufacturerName
 *    	"st rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0000 0x0005", "delay 250", // ModelIdentifier
 *    	"st rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0000 0x0006", "delay 250", // DateCode
 *    	"st rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0000 0x0007", "delay 250", // PowerSource
 *   	"st rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0000 0x0010", "delay 250", // LocationDescription
 *    	"st rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0000 0x0011", "delay 250", // PhysicalEnvironment
 *
 *    	"st rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0001 0x0000", "delay 250", // MainsVoltage
 *    	"st rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0001 0x0010", "delay 250", // MainsFrequency
 *    	"st rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0001 0x0020", "delay 250", // BatteryVoltage
 *
 *      "st rattr 0x${device.deviceNetworkId} 0x02 0x0006 0x0000", "delay 500", // On/Off
 *      "st rattr 0x${device.deviceNetworkId} 0x02 0x0006 0x0000", "delay 250", // On/Off
 *      "st rattr 0x${device.deviceNetworkId} 0x01 0x0002 0x0000", "delay 250" // CurrentTemperature
 *    ]
 * */
}

def configure() {
    if (state.debug) log.info "Configuring Reporting and Bindings."
	if (device.endpointId == null) device.endpointId = 2
    return zigbee.configureReporting(0x0006, 0x0000, 0x10, 0, 600, null) +
        zigbee.configureReporting(0x0008, 0x0000, 0x20, 1, 3600, 0x01) +
        zigbee.readAttribute(0x0006, 0x0000) +
        zigbee.readAttribute(0x0008, 0x0000)
}

private Integer convertHexToInt(hex) {
	Integer.parseInt(hex,16)
}
1 Like
Original & Aqara Xiaomi Zigbee Sensors (contact, temp, motion, button, outlet, leak, etc)
#136

Has anyone managed to get the virtual switches to work? I have been trying all day with different code and have got nowhere :frowning:

(Adam Walker) #137

Thank you !

(Andrey Glavchev) #138

In case you are using the double button versions of the wired switch: QBKG03LM and QBKG12LM (with neutral) I have updated the device handler proposed by @simic and @a4refillpad, to handle properly both control from the app and physically on the latest hub v2 firmware. I know you guys use virtual devices and smart things routines, not sure how it will work with those, but I use webCORE and it works good.

As I didn’t manage to find the original repos, I created my own: https://github.com/wastedabuser/aqara_wired_wall_switch

1 Like
Original & Aqara Xiaomi Zigbee Sensors (contact, temp, motion, button, outlet, leak, etc)
(John Doyle) #139

Thanks for the update. I have added your code to my code based on Github and credited you - thanks.

(Sterian Vlad) #140

Hello!

This means that the sync problem it’s solved?Or it’s just a update for DHT to work with the new firmware of hub?

LE: Can you share your webCORE piston with us, please?:smiley:

(Andrey Glavchev) #141

Yes, it is solved. You can use the state of each button in conditions or events. Even the Toggle function works. I’ve achieved a multiway switch using one wired and two wireless switched. I will post a piston as soon as i get back to PC.

(John Doyle) #142

Hi - moved and renamed the device handler so it will sync with development platforms linked to Github.

1 Like