Xiaomi Mijia WXKG01LM switch via zigbee2mqtt

I recently received a zigbee Xiaomi Mijia Wireless Switch, which can trigger on:

  • Single click
  • Double clicks
  • Triple clicks
  • Quadruple clicks
  • Many clicks (anything over four clicks is sent as many)
  • Long press (hold)
  • Long press (release)

It will also output the duration of the long press.

Here is how I integrated into openHAB, via zigbee2mqtt and Mosquitto.

Prerequisites

  • Ensure the openHAB MQTT binding is installed (V2, not V1)
  • My Mosquitto MQTT broker is setup as per default.
  • Pair the device with zigbee2mqtt as described here.
    • Ensure that you are able to pair devices by setting permit_join to true in configuration.yaml (usually in /opt/zigbee2mqtt/data)
  • Once paired, adjust the zigbee2mqtt configuration.yaml (usually in /opt/zigbee2mqtt/data) to:

Here is my configuration.yaml - your device ID is likely to be different. I have given my device the friendly name swButton:

homeassistant: false
permit_join: true
mqtt:
  base_topic: zigbee2mqtt
  server: 'mqtt://localhost'
serial:
  port: /dev/ttyACM0
  disable_led: false
advanced:
  log_level: error
  availability_timeout: 5
devices:
  '0x00158d0003d2bf4e':
    friendly_name: swButton
experimental:
  output: attribute

openHAB

MQTT bridge

I have a separate file which just contains the bridge Thing to my Mosquitto MQTT broker:

Bridge mqtt:broker:MosquittoMqttBroker "Mosquitto MQTT Broker" [
	host="192.168.1.92",
	secure=false,
	port=1883,
	clientID="OpenHAB2"
]

zigbee.things

//Mijia WXKG01LM button
Thing mqtt:topic:swButton "Mijia button" (mqtt:broker:MosquittoMqttBroker) {
    Channels:
        Type switch : availability "Reachable" [
            stateTopic = "zigbee2mqtt/swButton/availability",
            off="offline",
            on="online"
        ]
        Type number : battery "Battery level" [
            stateTopic = "zigbee2mqtt/swButton/battery"
        ]
        Type number : voltage "Battery voltage" [
            stateTopic = "zigbee2mqtt/swButton/voltage"
        ]
        Type number : linkquality "Link quality" [
            stateTopic = "zigbee2mqtt/swButton/linkquality"
        ]
        Type string : click "Click" [
            stateTopic = "zigbee2mqtt/swButton/click"
        ]
        Type number : click_duration "Click duration" [
            stateTopic = "zigbee2mqtt/swButton/duration"
        ]
}

zigbee.items

Switch sButtonReachable "Zigbee button reachable" (gReachable) { channel="mqtt:topic:swButton:availability" }
Number nButtonBattery { channel="mqtt:topic:swButton:battery" }
Number nButtonVoltage { channel="mqtt:topic:swButton:voltage" }
Number nButtonLinkQuality { channel="mqtt:topic:swButton:linkquality" }
String strButtonClick { channel="mqtt:topic:swButton:click" }
Number nButtonClickDuration { channel="mqtt:topic:swButton:click_duration" }

sitemap

image

Text item=sButtonReachable label="Button switch [MAP(switch2online.map):%s]" icon="wallswitch" valuecolor=["ON"="green", "OFF"="red", "NULL"="red", "-"="red"]
Text item=nButtonBattery label="Battery [%.0f %%]" icon="battery"
Text item=nButtonVoltage label="Voltage [%.0f mV]" icon="battery"
Text item=nButtonLinkQuality label="Link quality [%.0f]" icon="qualityofservice"
Text item=strButtonClick label="Last click action [%s]"
Text item=nButtonClickDuration label="Last long click duration [%.0f]" icon="time"

The switch2online.map file contains the below, saved into the transform folder:

OFF=OFFLINE
ON=ONLINE
NULL=UNDEFINED
-=-

Example rule

The following rule triggers when the switch is pressed, and performs an action depending on the click type:

DSL
rule "Mijia button pressed"
when
	Item strButtonClick received update
then
	//Switch through the different options
	switch strButtonClick.state {
		case "single":
			//Perform action on single click
			sUpstairsHallwayLight.sendCommand(ON)
		case "double":
			//Perform action on double click
			sUpstairsHallwayLight.sendCommand(OFF)
		case "triple":
			//Perform action on triple click
			sRGB1.sendCommand(ON)
		case "quadruple":
			//Perform action on quadruple click
			sRGB1.sendCommand(OFF)
		case "many":
			//Perform action on more than 4 clicks
			sRGB2.sendCommand(ON)
		case "long":
			//Perform action on long press whilst still pressed
			sRGB2.sendCommand(OFF)
		case "long_release":{
			//Perform action on long press when released
			sUpstairsHallwayLight.sendCommand(ON)

			if(nButtonClickDuration.state < 1000){
				//Short long press
			}
			else if(nButtonClickDuration.state < 2000){
				//Medium long press
			}
			else{
				//Long long press
			}
		}
	}
end
Jython

(I’m aware that the log entry could be sent before the IF statement, but there are understandable errors if I only have commented lines after each ELIF…)

from core.rules import rule
from core.triggers import when

'''
MIJIA SWITCH
Perform actions when the button is pressed
'''
@rule("Mijia switch pressed", description="Perform actions when the button is pressed")
@when("Item strButtonClick received update")
def action_mijia_switch_changed(event):
    
    click_type = items["strButtonClick"].toString()
    
    if click_type == "single" :
        #Perform action on single click
        action_mijia_switch_changed.log.info("{} click on the Mijia switch".format(click_type))
    elif click_type == "double" :
        #Perform action on double clicks
        action_mijia_switch_changed.log.info("{} click on the Mijia switch".format(click_type))
    elif click_type == "triple" :
        #Perform action on triple clicks
        action_mijia_switch_changed.log.info("{} click on the Mijia switch".format(click_type))
    elif click_type == "quadruple" :
        #Perform action on quadruple clicks
        action_mijia_switch_changed.log.info("{} click on the Mijia switch".format(click_type))
    elif click_type == "many" :
        #Perform action on many clicks
        action_mijia_switch_changed.log.info("{} click on the Mijia switch".format(click_type))
    elif click_type == "long" :
        #Perform action on long click hold
        action_mijia_switch_changed.log.info("{} click on the Mijia switch".format(click_type))
    elif click_type == "long_release" :
        #Perform action on long click release
        action_mijia_switch_changed.log.info("{} click on the Mijia switch".format(click_type))

        click_duration = float(items["nButtonClickDuration"].toString())

        if click_duration < 1000:
            #Perform action on short long press
            action_mijia_switch_changed.log.info("{} click duration on the Mijia switch".format(click_duration))
        elif click_duration < 2000:
            #Perform action on medium long press
            action_mijia_switch_changed.log.info("{} click duration on the Mijia switch".format(click_duration))
        else:
            #Perform action on long long press
            action_mijia_switch_changed.log.info("{} click duration on the Mijia switch".format(click_duration))

At this point in time, I am unsure of the units for long-click duration.

4 Likes

Thank you!